Skip to content

[forceinline] add Kunpeng forceinline optimization - #161

Merged
lxq015 merged 3 commits into
go1.26.5-zte-devfrom
forceinline
Sep 2, 2026
Merged

lxq015 merged 3 commits into
go1.26.5-zte-devfrom
forceinline

Conversation

@lxq015

@lxq015 lxq015 commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

[port] forceinline: add Kunpeng forceinline optimization for runtime hot paths

Port of https://gitcode.com/openeuler/golang/pull/66 to the ZTE RISC-V toolchain.

Summary

Adds a Kunpeng-targeted forceinline pass that forcibly inlines selected hot functions in runtime.mallocgc and related allocation/GC paths, bypassing the normal inline cost budget. The feature is fully gated by a new compiler debug flag and is off by default, so existing builds are unaffected.

Two new -d flags are introduced:

  • -d=forceinline=1 — enable the default force-inline function list
  • -d=forceinlinelog — print force-inline decision logs (for diagnostics)

Usage

./make.bash
GOMAXPROCS=1 go test -gcflags='all=-d=forceinline=1' -bench=BenchmarkMalloc -run=^$ -count=3 runtime/

Verification

1. Functional / correctness

Ran the bundled script test to verify the gating semantics:

Case Result
-d=forceinline=1 default list takes effect ✅
-d=forceinline=0 disables the feature ✅
-d=forceinline=2 rejected with -forceinline does not support setting to 2 ✅
-l has higher priority than forceinline ✅
Binary equivalence (two identical builds produce identical binaries) ✅

2. Benchmark

goos: linux
goarch: riscv64
pkg: runtime
cpu: Spacemit(R) X60 
                 │before_noforceinline │  forceinline_withmallocgc  │ forceinline_nomallocgc │
                  │       sec/op        │   sec/op    vs base         │   sec/op     vs base          │
Malloc8            101.1n ± 7%   104.3n ± 9%       ~ (p=0.485)         101.8n ± 3%       ~ (p=0.900)
Malloc16           178.8n ± 3%   171.4n ± 1%  -4.17% (p=0.002)         178.1n ± 1%  -0.42% (p=0.006)
Malloc32           214.9n ± 2%   211.3n ± 0%  -1.70% (p=0.002)         215.6n ± 1%       ~ (p=0.818)
MallocTypeInfo8    152.4n ± 2%   143.6n ± 1%  -5.81% (p=0.002)         152.7n ± 7%       ~ (p=0.818)
MallocTypeInfo16   198.2n ± 9%   211.0n ± 3%       ~ (p=0.065)         209.3n ± 5%       ~ (p=0.132)
MallocTypeInfo32   242.3n ± 2%   231.1n ± 3%  -4.62% (p=0.002)         236.5n ± 2%  -2.37% (p=0.009)
MallocLargeStruct  1.433µ ± 1%   1.380µ ± 1%  -3.70% (p=0.002)         1.423µ ± 2%       ~ (p=0.329)
geomean            236.0n        232.3n      -1.56%                    237.1n       +0.46%

The default forceinline set (which includes mallocgc) shows a -1.56% improvement relative to the baseline, with 5 statistically significant items (p=0.002). Excluding mallocgc from the forceinline set results in a +0.46% regression relative to the baseline.

Notes

The default force-inline function list was adapted for the Go 1.26.5 runtime layout (runtime.scanobject → runtime.scanObject; removed writeHeapBits.*, mallocgc1/2, deductAssistCredit2, which no longer exist in this version). See the in-code comment: "You may need update this list when you update the go version."

@wangpc-pp wangpc-pp left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+2.

Comment thread src/cmd/compile/internal/base/debug.go Outdated
WrapGlobalMapDbg int `help:"debug trace output for global map init wrapping"`
WrapGlobalMapCtl int `help:"global map init wrap control (0 => default, 1 => off, 2 => stress mode, no size cutoff)"`
ZeroCopy int `help:"enable zero-copy string->[]byte conversions" concurrent:"ok"`
ForceInline int `help:"enable force inline"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add concurrent:"ok" here. Without this tag, the compiler will set ConcurrentOk=false and force the backend worker count to 1, which will significantly increase build time.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thank you, fixed.

lxq015 and others added 2 commits August 20, 2026 11:43
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@BoyaoWang430 BoyaoWang430 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1

@ctk-1998 ctk-1998 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1

case 1:
// Add default force inline function list.
// You may need update this list when you update the go version.
forceInlineMap = map[string]struct{}{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Given that Go versions are subject to upgrades, the function list here may require updates accordingly; a means of recording this pending action is needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thank you for your suggestion. I've added assertion-based tests (TestScript/forceinline) that verify every function in the force-inline list is actually force-inlined. This acts as a safety net: if we upgrade the Go version but forget to adapt the list, the test will fail and all.bash will catch it.

@ctk-1998 ctk-1998 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we have any performance data?


"runtime.mallocgcSmallScanNoHeader": {},

"runtime.mallocgc": {},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IIUC, runtime.mallocgc has a high cost. If we force it to be inlined by default, it would significantly increase pressure of i-cache, resulting in performance degradation rather than improvement. Has this function been tested independently?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, the default forceinline set (which includes mallocgc) improves performance by 1.56% over the baseline, with 5 statistically significant results (p=0.002). Excluding mallocgc from the forceinline set leads to a 0.46% regression. Benchmark results have also been added to the PR description.

@newborn22 newborn22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+2

@lxq015
lxq015 merged commit 2164d3a into go1.26.5-zte-dev Sep 2, 2026
6 of 7 checks passed
@github-actions
github-actions Bot deleted the forceinline branch September 2, 2026 01:37
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.

5 participants