Skip to content

Instantly share code, notes, and snippets.

@lizthegrey
Last active August 16, 2026 15:14
Show Gist options
  • Select an option

  • Save lizthegrey/5372c06fa75dd477d47f1c5899ee7364 to your computer and use it in GitHub Desktop.

Select an option

Save lizthegrey/5372c06fa75dd477d47f1c5899ee7364 to your computer and use it in GitHub Desktop.
arm64 NEON vs GP memmove loop micro-benchmark (golang/go#80899)

arm64 NEON vs scalar memmove loop micro-benchmark

Supporting data for golang/go#80899.

This is not a benchmark of CL 692295. It's a minimal, standalone micro-benchmark isolating just the loop shape question — paired scalar LDP/STP (copyGP, matching runtime.memmove's current arm64 implementation) vs. a single 4-register NEON VLD1.P/VST1.P per 64-byte chunk (copyNEON) — with no alignment fixup, no software pipelining, and no overlap handling. src/dst are fixed, page-resident arenas shared by both variants and every size, so the two variants always operate on identical addresses (an earlier version allocated fresh slices per size per variant and got misleading, address-dependent cache-aliasing noise at large sizes — fixed by switching to shared arenas).

Files

  • copy_arm64.s, copy_arm64.go, copy_test.go — the harness. go test -run TestCorrectness verifies byte-for-byte correctness at every size first; go test -bench . runs the timing comparison.
  • benchstat-*.txt — full benchstat output (-count=7, so n=7 samples per point) for each of the four cores tested: AWS Graviton3/4/5 (Neoverse V1/V2/V3) and an Ampere Altra (Neoverse N1). Negative % = NEON faster.

Headline result

NEON wins on all four cores, no exceptions, from 128B up to ~32KiB. Above ~32-48KiB the three Graviton (V-series) cores flip to a small, consistent scalar advantage that holds out to the largest size tested (1MiB); the Neoverse N1 core does not flip and keeps favoring NEON throughout.

goos: linux
goarch: arm64
pkg: memcpybench
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/oracle-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/oracle-neon2.txt │
│ sec/op │ sec/op vs base │
/128-4 6.963n ± 2% 6.771n ± 0% -2.76% (p=0.002 n=7)
/192-4 8.015n ± 2% 7.379n ± 0% -7.94% (p=0.001 n=7)
/256-4 9.416n ± 2% 8.723n ± 1% -7.36% (p=0.001 n=7)
/320-4 10.84n ± 2% 10.12n ± 0% -6.64% (p=0.001 n=7)
/384-4 12.26n ± 1% 11.43n ± 0% -6.77% (p=0.001 n=7)
/448-4 13.83n ± 0% 12.74n ± 1% -7.88% (p=0.001 n=7)
/512-4 14.87n ± 0% 14.09n ± 0% -5.25% (p=0.001 n=7)
/640-4 17.82n ± 0% 16.84n ± 1% -5.50% (p=0.001 n=7)
/768-4 20.35n ± 1% 19.44n ± 0% -4.47% (p=0.001 n=7)
/896-4 23.21n ± 1% 22.16n ± 0% -4.52% (p=0.001 n=7)
/1024-4 25.84n ± 0% 24.81n ± 0% -3.99% (p=0.001 n=7)
/1280-4 31.18n ± 0% 30.19n ± 1% -3.18% (p=0.001 n=7)
/1536-4 36.61n ± 1% 35.52n ± 0% -2.98% (p=0.001 n=7)
/1792-4 41.87n ± 0% 40.89n ± 1% -2.34% (p=0.001 n=7)
/2048-4 47.19n ± 1% 46.22n ± 0% -2.06% (p=0.001 n=7)
/2560-4 57.99n ± 1% 57.07n ± 0% -1.59% (p=0.001 n=7)
/3072-4 68.72n ± 0% 67.63n ± 0% -1.59% (p=0.001 n=7)
/3584-4 79.41n ± 1% 78.38n ± 0% -1.30% (p=0.001 n=7)
/4096-4 90.09n ± 0% 89.16n ± 0% -1.03% (p=0.001 n=7)
/4608-4 139.3n ± 1% 132.8n ± 1% -4.67% (p=0.001 n=7)
/5120-4 184.7n ± 0% 170.3n ± 1% -7.80% (p=0.001 n=7)
/6144-4 274.5n ± 0% 247.0n ± 3% -10.02% (p=0.001 n=7)
/7168-4 364.6n ± 1% 320.3n ± 1% -12.15% (p=0.001 n=7)
/8192-4 452.8n ± 0% 393.0n ± 1% -13.21% (p=0.001 n=7)
/10240-4 565.1n ± 1% 490.2n ± 0% -13.25% (p=0.001 n=7)
/12288-4 676.8n ± 1% 587.3n ± 0% -13.22% (p=0.001 n=7)
/16384-4 901.7n ± 4% 774.7n ± 1% -14.08% (p=0.001 n=7)
/24576-4 1.070µ ± 1% 1.056µ ± 0% -1.31% (p=0.001 n=7)
/32768-4 1.430µ ± 0% 1.410µ ± 0% -1.40% (p=0.001 n=7)
/49152-4 2.150µ ± 0% 2.120µ ± 0% -1.40% (p=0.001 n=7)
/65536-4 2.870µ ± 0% 2.831µ ± 1% -1.36% (p=0.001 n=7)
/98304-4 4.314µ ± 0% 4.258µ ± 1% -1.30% (p=0.001 n=7)
/131072-4 5.759µ ± 0% 5.681µ ± 0% -1.35% (p=0.001 n=7)
/196608-4 8.642µ ± 1% 8.520µ ± 0% -1.41% (p=0.001 n=7)
/262144-4 11.54µ ± 1% 11.38µ ± 0% -1.33% (p=0.001 n=7)
/393216-4 17.31µ ± 2% 17.07µ ± 0% -1.37% (p=0.001 n=7)
/524288-4 23.07µ ± 1% 22.73µ ± 0% -1.49% (p=0.001 n=7)
/786432-4 34.61µ ± 1% 34.14µ ± 1% -1.35% (p=0.001 n=7)
/1048576-4 46.21µ ± 0% 45.57µ ± 2% -1.38% (p=0.024 n=7)
geomean 243.6n 231.9n -4.81%
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/oracle-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/oracle-neon2.txt │
│ B/s │ B/s vs base │
/128-4 17.12Gi ± 3% 17.61Gi ± 0% +2.84% (p=0.001 n=7)
/192-4 22.31Gi ± 2% 24.23Gi ± 0% +8.62% (p=0.001 n=7)
/256-4 25.32Gi ± 2% 27.33Gi ± 1% +7.95% (p=0.001 n=7)
/320-4 27.49Gi ± 2% 29.46Gi ± 0% +7.16% (p=0.001 n=7)
/384-4 29.16Gi ± 1% 31.28Gi ± 0% +7.27% (p=0.001 n=7)
/448-4 30.17Gi ± 0% 32.75Gi ± 1% +8.52% (p=0.001 n=7)
/512-4 32.06Gi ± 0% 33.84Gi ± 0% +5.55% (p=0.001 n=7)
/640-4 33.45Gi ± 0% 35.41Gi ± 1% +5.84% (p=0.001 n=7)
/768-4 35.14Gi ± 1% 36.79Gi ± 0% +4.68% (p=0.001 n=7)
/896-4 35.95Gi ± 1% 37.65Gi ± 0% +4.73% (p=0.001 n=7)
/1024-4 36.90Gi ± 0% 38.45Gi ± 0% +4.19% (p=0.001 n=7)
/1280-4 38.23Gi ± 0% 39.49Gi ± 1% +3.29% (p=0.001 n=7)
/1536-4 39.08Gi ± 1% 40.27Gi ± 0% +3.06% (p=0.001 n=7)
/1792-4 39.86Gi ± 0% 40.82Gi ± 1% +2.39% (p=0.001 n=7)
/2048-4 40.42Gi ± 1% 41.27Gi ± 0% +2.09% (p=0.001 n=7)
/2560-4 41.11Gi ± 1% 41.77Gi ± 0% +1.62% (p=0.001 n=7)
/3072-4 41.63Gi ± 0% 42.30Gi ± 0% +1.61% (p=0.001 n=7)
/3584-4 42.03Gi ± 1% 42.59Gi ± 0% +1.31% (p=0.001 n=7)
/4096-4 42.34Gi ± 0% 42.79Gi ± 0% +1.04% (p=0.001 n=7)
/4608-4 30.80Gi ± 1% 32.31Gi ± 1% +4.88% (p=0.001 n=7)
/5120-4 25.82Gi ± 0% 27.99Gi ± 1% +8.43% (p=0.001 n=7)
/6144-4 20.85Gi ± 0% 23.17Gi ± 2% +11.12% (p=0.001 n=7)
/7168-4 18.31Gi ± 1% 20.84Gi ± 1% +13.82% (p=0.001 n=7)
/8192-4 16.85Gi ± 0% 19.42Gi ± 1% +15.23% (p=0.001 n=7)
/10240-4 16.88Gi ± 1% 19.45Gi ± 0% +15.27% (p=0.001 n=7)
/12288-4 16.91Gi ± 1% 19.49Gi ± 0% +15.24% (p=0.001 n=7)
/16384-4 16.92Gi ± 4% 19.70Gi ± 1% +16.38% (p=0.001 n=7)
/24576-4 21.39Gi ± 1% 21.67Gi ± 0% +1.31% (p=0.001 n=7)
/32768-4 21.34Gi ± 0% 21.64Gi ± 0% +1.40% (p=0.001 n=7)
/49152-4 21.29Gi ± 0% 21.59Gi ± 0% +1.42% (p=0.001 n=7)
/65536-4 21.26Gi ± 0% 21.56Gi ± 1% +1.38% (p=0.001 n=7)
/98304-4 21.22Gi ± 0% 21.50Gi ± 1% +1.31% (p=0.001 n=7)
/131072-4 21.20Gi ± 0% 21.49Gi ± 0% +1.37% (p=0.001 n=7)
/196608-4 21.19Gi ± 1% 21.49Gi ± 0% +1.43% (p=0.001 n=7)
/262144-4 21.16Gi ± 1% 21.45Gi ± 0% +1.34% (p=0.001 n=7)
/393216-4 21.15Gi ± 2% 21.45Gi ± 0% +1.39% (p=0.001 n=7)
/524288-4 21.16Gi ± 1% 21.48Gi ± 0% +1.51% (p=0.001 n=7)
/786432-4 21.16Gi ± 1% 21.45Gi ± 1% +1.37% (p=0.001 n=7)
/1048576-4 21.13Gi ± 0% 21.43Gi ± 2% +1.40% (p=0.026 n=7)
geomean 26.10Gi 27.42Gi +5.05%
goos: linux
goarch: arm64
pkg: memcpybench
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton3-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton3-neon2.txt │
│ sec/op │ sec/op vs base │
/128-4 5.423n ± 0% 4.380n ± 0% -19.23% (p=0.001 n=7)
/192-4 7.959n ± 0% 6.212n ± 1% -21.95% (p=0.001 n=7)
/256-4 9.649n ± 1% 7.555n ± 1% -21.70% (p=0.001 n=7)
/320-4 11.100n ± 0% 8.759n ± 1% -21.09% (p=0.001 n=7)
/384-4 12.420n ± 0% 9.444n ± 1% -23.96% (p=0.001 n=7)
/448-4 13.90n ± 1% 10.21n ± 0% -26.55% (p=0.001 n=7)
/512-4 15.81n ± 0% 11.14n ± 0% -29.54% (p=0.001 n=7)
/640-4 19.30n ± 0% 13.08n ± 0% -32.23% (p=0.001 n=7)
/768-4 22.61n ± 0% 14.79n ± 1% -34.59% (p=0.001 n=7)
/896-4 25.48n ± 0% 16.23n ± 2% -36.30% (p=0.001 n=7)
/1024-4 28.30n ± 0% 17.92n ± 0% -36.68% (p=0.001 n=7)
/1280-4 34.59n ± 0% 21.28n ± 0% -38.48% (p=0.001 n=7)
/1536-4 40.79n ± 0% 24.57n ± 1% -39.76% (p=0.001 n=7)
/1792-4 47.03n ± 0% 27.84n ± 0% -40.80% (p=0.001 n=7)
/2048-4 52.96n ± 0% 31.00n ± 0% -41.47% (p=0.001 n=7)
/2560-4 65.72n ± 0% 37.36n ± 0% -43.15% (p=0.001 n=7)
/3072-4 77.72n ± 0% 43.73n ± 0% -43.73% (p=0.001 n=7)
/3584-4 90.20n ± 0% 50.16n ± 0% -44.39% (p=0.001 n=7)
/4096-4 102.70n ± 0% 56.66n ± 0% -44.83% (p=0.001 n=7)
/4608-4 160.50n ± 3% 93.55n ± 0% -41.71% (p=0.001 n=7)
/5120-4 205.7n ± 0% 131.1n ± 0% -36.27% (p=0.001 n=7)
/6144-4 307.0n ± 0% 206.0n ± 0% -32.90% (p=0.001 n=7)
/7168-4 407.7n ± 0% 277.6n ± 0% -31.91% (p=0.001 n=7)
/8192-4 507.1n ± 0% 354.8n ± 0% -30.03% (p=0.001 n=7)
/10240-4 633.1n ± 0% 443.3n ± 0% -29.98% (p=0.001 n=7)
/12288-4 759.3n ± 0% 531.7n ± 0% -29.97% (p=0.001 n=7)
/16384-4 1011.0n ± 0% 708.5n ± 0% -29.92% (p=0.001 n=7)
/24576-4 1.515µ ± 0% 1.063µ ± 0% -29.83% (p=0.001 n=7)
/32768-4 2.019µ ± 0% 1.418µ ± 0% -29.77% (p=0.001 n=7)
/49152-4 2.144µ ± 0% 2.129µ ± 0% -0.70% (p=0.001 n=7)
/65536-4 2.849µ ± 1% 2.839µ ± 0% -0.35% (p=0.001 n=7)
/98304-4 4.261µ ± 0% 4.259µ ± 0% ~ (p=0.061 n=7)
/131072-4 5.672µ ± 0% 5.677µ ± 0% +0.09% (p=0.008 n=7)
/196608-4 8.491µ ± 0% 8.513µ ± 0% +0.26% (p=0.001 n=7)
/262144-4 11.30µ ± 0% 11.36µ ± 0% +0.48% (p=0.001 n=7)
/393216-4 16.95µ ± 0% 17.03µ ± 0% +0.51% (p=0.001 n=7)
/524288-4 22.58µ ± 0% 22.72µ ± 0% +0.60% (p=0.001 n=7)
/786432-4 33.89µ ± 0% 34.12µ ± 0% +0.67% (p=0.001 n=7)
/1048576-4 45.23µ ± 0% 45.51µ ± 0% +0.61% (p=0.001 n=7)
geomean 260.8n 192.4n -26.21%
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton3-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton3-neon2.txt │
│ B/s │ B/s vs base │
/128-4 21.98Gi ± 0% 27.22Gi ± 0% +23.81% (p=0.001 n=7)
/192-4 22.47Gi ± 0% 28.78Gi ± 1% +28.12% (p=0.001 n=7)
/256-4 24.71Gi ± 1% 31.56Gi ± 1% +27.72% (p=0.001 n=7)
/320-4 26.85Gi ± 0% 34.02Gi ± 1% +26.73% (p=0.001 n=7)
/384-4 28.80Gi ± 0% 37.87Gi ± 1% +31.48% (p=0.001 n=7)
/448-4 30.01Gi ± 1% 40.87Gi ± 0% +36.19% (p=0.001 n=7)
/512-4 30.17Gi ± 0% 42.80Gi ± 0% +41.90% (p=0.001 n=7)
/640-4 30.89Gi ± 0% 45.57Gi ± 0% +47.54% (p=0.001 n=7)
/768-4 31.63Gi ± 0% 48.35Gi ± 1% +52.84% (p=0.001 n=7)
/896-4 32.75Gi ± 0% 51.41Gi ± 2% +56.98% (p=0.001 n=7)
/1024-4 33.70Gi ± 0% 53.21Gi ± 0% +57.89% (p=0.001 n=7)
/1280-4 34.46Gi ± 0% 56.02Gi ± 0% +62.56% (p=0.001 n=7)
/1536-4 35.07Gi ± 0% 58.22Gi ± 1% +66.02% (p=0.001 n=7)
/1792-4 35.49Gi ± 0% 59.94Gi ± 0% +68.91% (p=0.001 n=7)
/2048-4 36.02Gi ± 0% 61.54Gi ± 0% +70.86% (p=0.001 n=7)
/2560-4 36.28Gi ± 0% 63.82Gi ± 0% +75.91% (p=0.001 n=7)
/3072-4 36.81Gi ± 0% 65.43Gi ± 0% +77.75% (p=0.001 n=7)
/3584-4 37.01Gi ± 0% 66.54Gi ± 0% +79.80% (p=0.001 n=7)
/4096-4 37.13Gi ± 0% 67.33Gi ± 0% +81.32% (p=0.001 n=7)
/4608-4 26.74Gi ± 3% 45.87Gi ± 0% +71.56% (p=0.001 n=7)
/5120-4 23.18Gi ± 0% 36.38Gi ± 0% +56.95% (p=0.001 n=7)
/6144-4 18.64Gi ± 0% 27.77Gi ± 0% +49.00% (p=0.001 n=7)
/7168-4 16.37Gi ± 0% 24.04Gi ± 0% +46.85% (p=0.001 n=7)
/8192-4 15.04Gi ± 0% 21.50Gi ± 0% +42.92% (p=0.001 n=7)
/10240-4 15.06Gi ± 0% 21.52Gi ± 0% +42.83% (p=0.001 n=7)
/12288-4 15.07Gi ± 0% 21.53Gi ± 0% +42.82% (p=0.001 n=7)
/16384-4 15.10Gi ± 0% 21.54Gi ± 0% +42.64% (p=0.001 n=7)
/24576-4 15.11Gi ± 0% 21.53Gi ± 0% +42.52% (p=0.001 n=7)
/32768-4 15.12Gi ± 0% 21.52Gi ± 0% +42.36% (p=0.001 n=7)
/49152-4 21.36Gi ± 0% 21.50Gi ± 0% +0.66% (p=0.001 n=7)
/65536-4 21.42Gi ± 1% 21.50Gi ± 0% +0.37% (p=0.001 n=7)
/98304-4 21.49Gi ± 0% 21.50Gi ± 0% ~ (p=0.097 n=7)
/131072-4 21.52Gi ± 0% 21.50Gi ± 0% -0.07% (p=0.011 n=7)
/196608-4 21.56Gi ± 0% 21.51Gi ± 0% -0.26% (p=0.001 n=7)
/262144-4 21.60Gi ± 0% 21.50Gi ± 0% -0.47% (p=0.001 n=7)
/393216-4 21.61Gi ± 0% 21.50Gi ± 0% -0.50% (p=0.001 n=7)
/524288-4 21.62Gi ± 0% 21.49Gi ± 0% -0.60% (p=0.001 n=7)
/786432-4 21.61Gi ± 0% 21.47Gi ± 0% -0.67% (p=0.001 n=7)
/1048576-4 21.59Gi ± 0% 21.46Gi ± 0% -0.61% (p=0.001 n=7)
geomean 24.38Gi 33.05Gi +35.53%
goos: linux
goarch: arm64
pkg: memcpybench
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton4-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton4-neon2.txt │
│ sec/op │ sec/op vs base │
/128-4 4.487n ± 0% 3.960n ± 0% -11.75% (p=0.001 n=7)
/192-4 6.524n ± 0% 5.287n ± 0% -18.96% (p=0.001 n=7)
/256-4 7.512n ± 1% 6.464n ± 2% -13.95% (p=0.001 n=7)
/320-4 8.767n ± 0% 8.146n ± 1% -7.08% (p=0.001 n=7)
/384-4 10.140n ± 0% 8.875n ± 1% -12.48% (p=0.001 n=7)
/448-4 10.92n ± 0% 10.46n ± 1% -4.21% (p=0.001 n=7)
/512-4 11.77n ± 0% 10.72n ± 0% -8.92% (p=0.001 n=7)
/640-4 13.84n ± 0% 12.06n ± 1% -12.86% (p=0.001 n=7)
/768-4 16.43n ± 0% 13.49n ± 1% -17.89% (p=0.001 n=7)
/896-4 18.09n ± 0% 15.39n ± 0% -14.93% (p=0.001 n=7)
/1024-4 19.99n ± 0% 16.46n ± 1% -17.66% (p=0.001 n=7)
/1280-4 23.96n ± 0% 19.66n ± 2% -17.95% (p=0.001 n=7)
/1536-4 28.15n ± 0% 22.76n ± 1% -19.15% (p=0.001 n=7)
/1792-4 32.13n ± 0% 25.72n ± 1% -19.95% (p=0.001 n=7)
/2048-4 36.06n ± 1% 28.55n ± 0% -20.83% (p=0.001 n=7)
/2560-4 44.35n ± 0% 34.41n ± 0% -22.41% (p=0.001 n=7)
/3072-4 52.44n ± 1% 40.28n ± 0% -23.19% (p=0.001 n=7)
/3584-4 60.05n ± 1% 45.98n ± 0% -23.43% (p=0.001 n=7)
/4096-4 68.46n ± 0% 51.77n ± 0% -24.38% (p=0.001 n=7)
/4608-4 101.80n ± 0% 85.75n ± 0% -15.77% (p=0.001 n=7)
/5120-4 138.2n ± 0% 121.9n ± 0% -11.79% (p=0.001 n=7)
/6144-4 206.6n ± 1% 189.2n ± 1% -8.42% (p=0.001 n=7)
/7168-4 275.7n ± 1% 257.0n ± 1% -6.78% (p=0.001 n=7)
/8192-4 348.1n ± 1% 335.3n ± 0% -3.68% (p=0.001 n=7)
/10240-4 437.1n ± 1% 419.5n ± 1% -4.03% (p=0.001 n=7)
/12288-4 512.5n ± 0% 492.8n ± 0% -3.84% (p=0.001 n=7)
/16384-4 693.0n ± 1% 664.9n ± 1% -4.05% (p=0.001 n=7)
/24576-4 1031.0n ± 0% 991.5n ± 0% -3.83% (p=0.001 n=7)
/32768-4 1.374µ ± 0% 1.324µ ± 0% -3.64% (p=0.001 n=7)
/49152-4 1.968µ ± 0% 1.998µ ± 0% +1.52% (p=0.001 n=7)
/65536-4 2.618µ ± 0% 2.662µ ± 0% +1.68% (p=0.001 n=7)
/98304-4 3.919µ ± 0% 3.989µ ± 0% +1.79% (p=0.001 n=7)
/131072-4 5.228µ ± 0% 5.319µ ± 0% +1.74% (p=0.001 n=7)
/196608-4 7.811µ ± 0% 7.969µ ± 0% +2.02% (p=0.001 n=7)
/262144-4 10.40µ ± 0% 10.62µ ± 0% +2.12% (p=0.001 n=7)
/393216-4 15.59µ ± 0% 15.92µ ± 0% +2.17% (p=0.001 n=7)
/524288-4 20.77µ ± 0% 21.23µ ± 0% +2.19% (p=0.001 n=7)
/786432-4 31.12µ ± 0% 31.82µ ± 0% +2.25% (p=0.001 n=7)
/1048576-4 41.48µ ± 0% 42.40µ ± 0% +2.21% (p=0.001 n=7)
geomean 197.5n 178.5n -9.62%
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton4-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton4-neon2.txt │
│ B/s │ B/s vs base │
/128-4 26.57Gi ± 0% 30.11Gi ± 0% +13.30% (p=0.001 n=7)
/192-4 27.41Gi ± 0% 33.82Gi ± 0% +23.40% (p=0.001 n=7)
/256-4 31.74Gi ± 1% 36.88Gi ± 2% +16.21% (p=0.001 n=7)
/320-4 33.99Gi ± 0% 36.59Gi ± 1% +7.62% (p=0.001 n=7)
/384-4 35.25Gi ± 0% 40.30Gi ± 1% +14.31% (p=0.001 n=7)
/448-4 38.20Gi ± 0% 39.87Gi ± 1% +4.36% (p=0.001 n=7)
/512-4 40.50Gi ± 0% 44.47Gi ± 0% +9.78% (p=0.001 n=7)
/640-4 43.06Gi ± 0% 49.44Gi ± 1% +14.83% (p=0.001 n=7)
/768-4 43.54Gi ± 0% 53.02Gi ± 1% +21.76% (p=0.001 n=7)
/896-4 46.12Gi ± 0% 54.21Gi ± 0% +17.53% (p=0.001 n=7)
/1024-4 47.70Gi ± 0% 57.94Gi ± 1% +21.46% (p=0.001 n=7)
/1280-4 49.76Gi ± 0% 60.63Gi ± 2% +21.84% (p=0.001 n=7)
/1536-4 50.81Gi ± 0% 62.85Gi ± 1% +23.69% (p=0.001 n=7)
/1792-4 51.95Gi ± 0% 64.88Gi ± 1% +24.89% (p=0.001 n=7)
/2048-4 52.90Gi ± 1% 66.81Gi ± 0% +26.29% (p=0.001 n=7)
/2560-4 53.76Gi ± 0% 69.29Gi ± 1% +28.88% (p=0.001 n=7)
/3072-4 54.56Gi ± 1% 71.03Gi ± 0% +30.18% (p=0.001 n=7)
/3584-4 55.59Gi ± 1% 72.60Gi ± 0% +30.60% (p=0.001 n=7)
/4096-4 55.72Gi ± 0% 73.69Gi ± 0% +32.23% (p=0.001 n=7)
/4608-4 42.14Gi ± 0% 50.05Gi ± 0% +18.77% (p=0.001 n=7)
/5120-4 34.51Gi ± 0% 39.11Gi ± 0% +13.34% (p=0.001 n=7)
/6144-4 27.70Gi ± 1% 30.25Gi ± 1% +9.21% (p=0.001 n=7)
/7168-4 24.21Gi ± 1% 25.98Gi ± 1% +7.28% (p=0.001 n=7)
/8192-4 21.92Gi ± 1% 22.75Gi ± 0% +3.80% (p=0.001 n=7)
/10240-4 21.82Gi ± 1% 22.73Gi ± 1% +4.19% (p=0.001 n=7)
/12288-4 22.33Gi ± 0% 23.22Gi ± 0% +4.01% (p=0.001 n=7)
/16384-4 22.02Gi ± 1% 22.95Gi ± 1% +4.23% (p=0.001 n=7)
/24576-4 22.19Gi ± 0% 23.08Gi ± 0% +4.03% (p=0.001 n=7)
/32768-4 22.22Gi ± 0% 23.05Gi ± 0% +3.73% (p=0.001 n=7)
/49152-4 23.26Gi ± 0% 22.92Gi ± 0% -1.48% (p=0.001 n=7)
/65536-4 23.31Gi ± 0% 22.93Gi ± 0% -1.65% (p=0.001 n=7)
/98304-4 23.36Gi ± 0% 22.95Gi ± 0% -1.74% (p=0.001 n=7)
/131072-4 23.35Gi ± 0% 22.95Gi ± 0% -1.71% (p=0.001 n=7)
/196608-4 23.44Gi ± 0% 22.98Gi ± 0% -1.99% (p=0.001 n=7)
/262144-4 23.47Gi ± 0% 22.99Gi ± 0% -2.08% (p=0.001 n=7)
/393216-4 23.50Gi ± 0% 23.00Gi ± 0% -2.12% (p=0.001 n=7)
/524288-4 23.51Gi ± 0% 23.01Gi ± 0% -2.14% (p=0.001 n=7)
/786432-4 23.53Gi ± 0% 23.02Gi ± 0% -2.20% (p=0.001 n=7)
/1048576-4 23.54Gi ± 0% 23.03Gi ± 0% -2.16% (p=0.001 n=7)
geomean 32.18Gi 35.61Gi +10.65%
goos: linux
goarch: arm64
pkg: memcpybench
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton5-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton5-neon2.txt │
│ sec/op │ sec/op vs base │
/128-4 3.354n ± 0% 3.196n ± 1% -4.71% (p=0.001 n=7)
/192-4 4.919n ± 1% 4.170n ± 0% -15.23% (p=0.001 n=7)
/256-4 5.998n ± 1% 6.532n ± 2% +8.90% (p=0.001 n=7)
/320-4 6.666n ± 0% 6.644n ± 1% -0.33% (p=0.001 n=7)
/384-4 7.186n ± 0% 7.587n ± 0% +5.58% (p=0.001 n=7)
/448-4 7.791n ± 0% 8.254n ± 1% +5.94% (p=0.001 n=7)
/512-4 8.517n ± 0% 8.816n ± 0% +3.51% (p=0.001 n=7)
/640-4 10.06n ± 0% 10.03n ± 0% -0.30% (p=0.001 n=7)
/768-4 11.77n ± 0% 11.07n ± 1% -5.95% (p=0.001 n=7)
/896-4 13.02n ± 0% 12.47n ± 0% -4.22% (p=0.001 n=7)
/1024-4 14.37n ± 0% 13.72n ± 0% -4.52% (p=0.001 n=7)
/1280-4 17.02n ± 0% 16.21n ± 0% -4.76% (p=0.001 n=7)
/1536-4 19.43n ± 0% 18.56n ± 0% -4.48% (p=0.001 n=7)
/1792-4 21.89n ± 0% 21.06n ± 0% -3.79% (p=0.001 n=7)
/2048-4 24.43n ± 1% 23.53n ± 0% -3.68% (p=0.001 n=7)
/2560-4 29.39n ± 1% 28.31n ± 0% -3.67% (p=0.001 n=7)
/3072-4 34.19n ± 0% 33.38n ± 0% -2.37% (p=0.001 n=7)
/3584-4 39.09n ± 1% 38.05n ± 0% -2.66% (p=0.001 n=7)
/4096-4 43.90n ± 0% 43.06n ± 0% -1.91% (p=0.001 n=7)
/4608-4 74.67n ± 0% 68.63n ± 0% -8.09% (p=0.001 n=7)
/5120-4 106.40n ± 0% 99.20n ± 0% -6.77% (p=0.001 n=7)
/6144-4 167.7n ± 1% 157.4n ± 0% -6.14% (p=0.001 n=7)
/7168-4 231.6n ± 1% 216.2n ± 0% -6.65% (p=0.001 n=7)
/8192-4 292.3n ± 1% 283.7n ± 1% -2.94% (p=0.001 n=7)
/10240-4 363.3n ± 0% 355.0n ± 1% -2.28% (p=0.001 n=7)
/12288-4 425.7n ± 0% 414.6n ± 0% -2.61% (p=0.001 n=7)
/16384-4 580.4n ± 1% 560.5n ± 1% -3.43% (p=0.001 n=7)
/24576-4 857.1n ± 0% 837.0n ± 0% -2.35% (p=0.001 n=7)
/32768-4 1.142µ ± 0% 1.119µ ± 0% -2.01% (p=0.001 n=7)
/49152-4 1.682µ ± 0% 1.709µ ± 0% +1.61% (p=0.001 n=7)
/65536-4 2.240µ ± 0% 2.281µ ± 0% +1.83% (p=0.001 n=7)
/98304-4 3.355µ ± 0% 3.406µ ± 0% +1.52% (p=0.001 n=7)
/131072-4 4.470µ ± 0% 4.537µ ± 0% +1.50% (p=0.001 n=7)
/196608-4 6.696µ ± 0% 6.800µ ± 0% +1.55% (p=0.001 n=7)
/262144-4 8.919µ ± 0% 9.059µ ± 0% +1.57% (p=0.001 n=7)
/393216-4 13.36µ ± 0% 13.58µ ± 0% +1.70% (p=0.001 n=7)
/524288-4 17.79µ ± 0% 18.10µ ± 0% +1.71% (p=0.001 n=7)
/786432-4 26.67µ ± 0% 27.11µ ± 0% +1.64% (p=0.001 n=7)
/1048576-4 35.50µ ± 0% 36.15µ ± 0% +1.83% (p=0.001 n=7)
geomean 152.1n 149.4n -1.78%
│ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton5-gp2.txt │ /home/lizf/.claude/jobs/619411e5/tmp/benchstat/graviton5-neon2.txt │
│ B/s │ B/s vs base │
/128-4 35.54Gi ± 0% 37.30Gi ± 1% +4.96% (p=0.001 n=7)
/192-4 36.35Gi ± 1% 42.89Gi ± 0% +17.98% (p=0.001 n=7)
/256-4 39.75Gi ± 1% 36.50Gi ± 2% -8.18% (p=0.001 n=7)
/320-4 44.71Gi ± 0% 44.86Gi ± 1% +0.33% (p=0.001 n=7)
/384-4 49.76Gi ± 0% 47.14Gi ± 0% -5.28% (p=0.001 n=7)
/448-4 53.56Gi ± 0% 50.55Gi ± 1% -5.62% (p=0.001 n=7)
/512-4 55.99Gi ± 0% 54.09Gi ± 0% -3.39% (p=0.001 n=7)
/640-4 59.25Gi ± 0% 59.41Gi ± 0% +0.27% (p=0.001 n=7)
/768-4 60.79Gi ± 0% 64.63Gi ± 1% +6.32% (p=0.001 n=7)
/896-4 64.11Gi ± 0% 66.93Gi ± 0% +4.39% (p=0.001 n=7)
/1024-4 66.37Gi ± 0% 69.51Gi ± 0% +4.73% (p=0.001 n=7)
/1280-4 70.02Gi ± 0% 73.54Gi ± 0% +5.03% (p=0.001 n=7)
/1536-4 73.61Gi ± 0% 77.07Gi ± 0% +4.71% (p=0.001 n=7)
/1792-4 76.25Gi ± 0% 79.25Gi ± 0% +3.94% (p=0.001 n=7)
/2048-4 78.06Gi ± 1% 81.05Gi ± 0% +3.83% (p=0.001 n=7)
/2560-4 81.12Gi ± 1% 84.22Gi ± 0% +3.82% (p=0.001 n=7)
/3072-4 83.67Gi ± 1% 85.72Gi ± 0% +2.45% (p=0.001 n=7)
/3584-4 85.39Gi ± 1% 87.73Gi ± 0% +2.74% (p=0.001 n=7)
/4096-4 86.89Gi ± 0% 88.59Gi ± 0% +1.96% (p=0.001 n=7)
/4608-4 57.47Gi ± 0% 62.53Gi ± 0% +8.81% (p=0.001 n=7)
/5120-4 44.82Gi ± 0% 48.07Gi ± 0% +7.26% (p=0.001 n=7)
/6144-4 34.11Gi ± 1% 36.36Gi ± 0% +6.60% (p=0.001 n=7)
/7168-4 28.83Gi ± 1% 30.88Gi ± 0% +7.14% (p=0.001 n=7)
/8192-4 26.10Gi ± 1% 26.89Gi ± 1% +3.04% (p=0.001 n=7)
/10240-4 26.25Gi ± 0% 26.86Gi ± 1% +2.35% (p=0.001 n=7)
/12288-4 26.88Gi ± 0% 27.60Gi ± 0% +2.68% (p=0.001 n=7)
/16384-4 26.29Gi ± 1% 27.22Gi ± 1% +3.55% (p=0.001 n=7)
/24576-4 26.70Gi ± 0% 27.35Gi ± 0% +2.40% (p=0.001 n=7)
/32768-4 26.73Gi ± 0% 27.28Gi ± 0% +2.05% (p=0.001 n=7)
/49152-4 27.22Gi ± 0% 26.79Gi ± 0% -1.57% (p=0.001 n=7)
/65536-4 27.24Gi ± 0% 26.76Gi ± 0% -1.79% (p=0.001 n=7)
/98304-4 27.29Gi ± 0% 26.88Gi ± 0% -1.49% (p=0.001 n=7)
/131072-4 27.31Gi ± 0% 26.90Gi ± 0% -1.49% (p=0.001 n=7)
/196608-4 27.35Gi ± 0% 26.93Gi ± 0% -1.53% (p=0.001 n=7)
/262144-4 27.37Gi ± 0% 26.95Gi ± 0% -1.55% (p=0.001 n=7)
/393216-4 27.42Gi ± 0% 26.96Gi ± 0% -1.67% (p=0.001 n=7)
/524288-4 27.45Gi ± 0% 26.98Gi ± 0% -1.69% (p=0.001 n=7)
/786432-4 27.46Gi ± 0% 27.02Gi ± 0% -1.61% (p=0.001 n=7)
/1048576-4 27.51Gi ± 0% 27.01Gi ± 0% -1.80% (p=0.001 n=7)
geomean 41.79Gi 42.55Gi +1.81%
package memcpybench
import "unsafe"
// copyGP and copyNEON copy n bytes from src to dst.
// n must be a positive multiple of 64. Non-overlapping only.
func copyGP(dst, src unsafe.Pointer, n int)
func copyNEON(dst, src unsafe.Pointer, n int)
#include "textflag.h"
// func copyGP(dst, src unsafe.Pointer, n int)
// n must be a positive multiple of 64.
// Plain (non-software-pipelined) 64B/iteration copy using
// paired 64-bit GP loads/stores, mirroring the register-width
// technique runtime.memmove uses today on arm64.
TEXT ·copyGP(SB), NOSPLIT, $0-24
MOVD dst+0(FP), R0
MOVD src+8(FP), R1
MOVD n+16(FP), R2
loop:
LDP (R1), (R6, R7)
LDP 16(R1), (R8, R9)
LDP 32(R1), (R10, R11)
LDP 48(R1), (R12, R13)
STP (R6, R7), (R0)
STP (R8, R9), 16(R0)
STP (R10, R11), 32(R0)
STP (R12, R13), 48(R0)
ADD $64, R1
ADD $64, R0
SUBS $64, R2
BNE loop
RET
// func copyNEON(dst, src unsafe.Pointer, n int)
// n must be a positive multiple of 64.
// Same 64B/iteration shape, but using a single 4-register NEON
// LD1/ST1 to move the whole 64B chunk per instruction instead of
// four separate GP LDP/STP pairs.
TEXT ·copyNEON(SB), NOSPLIT, $0-24
MOVD dst+0(FP), R0
MOVD src+8(FP), R1
MOVD n+16(FP), R2
loop:
VLD1.P 64(R1), [V0.B16, V1.B16, V2.B16, V3.B16]
VST1.P [V0.B16, V1.B16, V2.B16, V3.B16], 64(R0)
SUBS $64, R2
BNE loop
RET
package memcpybench
import (
"testing"
"unsafe"
)
var sizes = []int{
128, 192, 256, 320, 384, 448, 512, 640, 768, 896,
1024, 1280, 1536, 1792, 2048, 2560, 3072, 3584, 4096,
4608, 5120, 6144, 7168, 8192, 10240, 12288, 16384, 24576, 32768,
49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576,
}
// Fixed, package-level arenas shared by both benchmark variants and every
// size. Earlier runs allocated fresh src/dst slices per size per variant
// (via make()), which let the allocator hand GP and NEON different
// addresses at each size -- for sizes near L1/L2 capacity that produced
// address-dependent cache-set aliasing that differed between the two
// variants and swamped the real signal (wild, reproducible +/-100%+
// swings at the same absolute sizes across independent machines). Using
// one arena pair for everything removes that degree of freedom: GP and
// NEON now always operate on the exact same addresses for a given size.
const arenaSize = 4 << 20 // 4 MiB, 4x the largest tested size
var (
srcArena = make([]byte, arenaSize)
dstArena = make([]byte, arenaSize)
)
func BenchmarkGP(b *testing.B) {
for _, n := range sizes {
src := srcArena[:n]
dst := dstArena[:n]
b.Run(sizeName(n), func(b *testing.B) {
b.SetBytes(int64(n))
for i := 0; i < b.N; i++ {
copyGP(unsafe.Pointer(&dst[0]), unsafe.Pointer(&src[0]), n)
}
})
}
}
func BenchmarkNEON(b *testing.B) {
for _, n := range sizes {
src := srcArena[:n]
dst := dstArena[:n]
b.Run(sizeName(n), func(b *testing.B) {
b.SetBytes(int64(n))
for i := 0; i < b.N; i++ {
copyNEON(unsafe.Pointer(&dst[0]), unsafe.Pointer(&src[0]), n)
}
})
}
}
func TestCorrectness(t *testing.T) {
for _, n := range sizes {
src := make([]byte, n)
for i := range src {
src[i] = byte(i)
}
for _, fn := range []func(dst, src unsafe.Pointer, n int){copyGP, copyNEON} {
dst := make([]byte, n)
fn(unsafe.Pointer(&dst[0]), unsafe.Pointer(&src[0]), n)
for i := range src {
if dst[i] != src[i] {
t.Fatalf("n=%d: mismatch at %d: got %d want %d", n, i, dst[i], src[i])
}
}
}
}
}
func sizeName(n int) string {
return itoa(n)
}
func itoa(n int) string {
if n == 0 {
return "0"
}
var buf [20]byte
i := len(buf)
for n > 0 {
i--
buf[i] = byte('0' + n%10)
n /= 10
}
return string(buf[i:])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment