Skip to content

Conversation

KobeArthurScofield
Copy link
Contributor

@KobeArthurScofield KobeArthurScofield commented Aug 16, 2025

#4952 (comment)

主要参数说明来源于

https://github.com/golang/go/blob/6e676ab2b809d46623acb5988248d95d1eb7939c/src/cmd/compile/internal/gc/main.go#L133-L141

https://github.com/golang/go/blob/6e676ab2b809d46623acb5988248d95d1eb7939c/src/cmd/compile/internal/inline/inl.go#L9-L18

https://github.com/golang/go/blob/6e676ab2b809d46623acb5988248d95d1eb7939c/src/cmd/compile/internal/inline/inl.go#L47-L62

-gcflags="-l=4" 目前应该是在不改动环境变量不添加 GOEXPERIMENT 下的比默认情况下激进的内联了(连带 non leaf functions),不过不改变内联节点限制,所以主线 common.go 也有不能内联的内容。

all=-l=4 连带依赖外部包一起处理(32 位 MIPS 无缘,最多只能 -l=4,不然直接不出货)

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

Windows 64 和 Linux 64 上的二进制会大多少?

@Fangliding
Copy link
Member

Fangliding commented Aug 16, 2025

-l 不是禁用内联吗
哦藏得很深的文档调数字可以激进策略

@KobeArthurScofield
Copy link
Contributor Author

KobeArthurScofield commented Aug 16, 2025

非常激进的话 x86-64 架构的大个 13% 左右吧
一般激进几乎没什么变化,最多让打包有点轻微变化

系统 默认 -gcflags="-l=4" -gcflags="all=-l=4"
Linux (amd64) 30,052,500 30,052,500 34,037,908 (+13.26%, +3.80MB)
Windows (amd64) 29,251,584 29,251,584 33,050,624 (+12.99%, +3.62MB)

@Fangliding
Copy link
Member

依稀记得当初没要的acme是膨胀6%

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

ACME 那个是真的没必要,用 core 起 TLS 都用 REALITY 去了

这个是用空间换时间,core 的整体运行效率都会高很多

@RPRX RPRX changed the title Build: Use more aggressive inlining Build: Use more aggressive inlining for higher efficiency Aug 16, 2025
@RPRX RPRX merged commit 2485f48 into XTLS:main Aug 16, 2025
39 checks passed
@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

话说这个 more aggressive 是不是 most aggressive?有没有更激进的

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

all=-l=4 这个 4 是不是还可以继续调大

@KobeArthurScofield
Copy link
Contributor Author

KobeArthurScofield commented Aug 16, 2025

应该是目前已知最接近 most 的,谁知道 Go 会不会在哪里埋了东西

按照代码注释标记来说,0(不开启),1(默认),2/3(同 1 但是开启编译下显示哪些可以被处理),4(多一个中间函数可以 inline),别的就没见到写了

@Fangliding
Copy link
Member

image 难道不是这个吗

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

我知道这个,但可以试试改成 5 有没有惊喜

还有 80 个节点的限制能调大吗

@KobeArthurScofield
Copy link
Contributor Author

我知道这个,但可以试试改成 5 有没有惊喜

没有直接可见的惊喜

还有 80 个节点的限制能调大吗

目前看来要叉个 Go 改 cmd/compile/internal/inline/inl.go,可能不利于可重复构建

@RPRX

This comment was marked as outdated.

@Fangliding
Copy link
Member

依赖也是 l=1

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

依赖也是 l=1

出处请求,因为确实是不用 all 的话体积没变

@Fangliding
Copy link
Member

Fangliding commented Aug 16, 2025

image

事情诡异了起来 哎就这样吧

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

确实挺诡异的

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

重新试一遍?

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

看起来就只是 xrayl0 和 xrayl1 的体积反过来了,根据 xrayl4 能看出应该是用了 all

@KobeArthurScofield
Copy link
Contributor Author

@KobeArthurScofield
Copy link
Contributor Author

看起来就只是 xrayl0 和 xrayl1 的体积反过来了,根据 xrayl4 能看出应该是用了 all

xrayl0 就是默认情况,只是 Go 那边这个参数在小于等于 1 的时候会做反转处理

@Fangliding
Copy link
Member

代码里面的注释是0禁用 1默认 看起来的gcflag里是10倒转了 1禁用0启用 不过我测的时候是直接比的没有gcflag和l=4 那只是聊天的时候稍微混乱了一点点 结论没变

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

基于默认编译测一下 //go:inline 和 //go:noinline 吧

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

针对 VLESS encryption 的 DecodeHeader() 等函数,原因是它的 AST 节点数看起来超过了 80,默认不会被内联,即使 -l=4

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

群聊的时候把这点给忘了,这个函数绝对不会被编译器内联,只能指定变成内联

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

image

事情诡异了起来 哎就这样吧

话说既然 -l 不等于 -l=0,说明 Golang 能区分这俩,不懂搞个 0/1 反转有啥意义

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

我觉得 Golang 不对 AST 节点数超过 80 的函数内联应该是觉得太大的函数内联优化占比有限

但像 DecodeHeader() 这种最多的 23 3 3 l>>8 l 走那么顺畅的,不内联就有点亏

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

我不知道从哪看的有这个命令,我找找

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

有些博客有写,Google 搜索的 AI 也有写,我不知道

@wwqgtxx
Copy link
Contributor

wwqgtxx commented Aug 16, 2025

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

有些博客有写,Google 搜索的 AI 也有写,我不知道

被骗了,梦里啥呀,又没必要骗你们

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

话说可以给 Golang PR 个 //go:inline 和 proposal 个模板功能,但我提的那个插包能找出纯 padding 的 TLS bug 都没回应

@Fangliding
Copy link
Member

实际情况
根本没有 //go:inline 这样的功能
l=4 也不会让DecodeHeader被inline 它只是允许非叶子函数进行inline 不会改变80 budget的设定

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

#4952 (comment)

所以我说可以给 Golang PR 一个突破 AST 节点数 80 限制的 //go:inline

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

还有些博客写的是 -l 数字越大层级越多,更坑人了,实际上只有 0 1 4 这三个选项

@Fangliding
Copy link
Member

哎 AI幻觉

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

对吧,你 Google 搜索,置顶的 AI 也是一本正经地告诉你有,甚至还踏马有例子

但这也不太属于 AI 幻觉,属于是互联网上错误资料太多,就跟那 MPL 要交出版权给原作者一样,不知道最初哪个人才写的

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

leaf 函数的问题,Golang 应该是认为如果一个函数里面有其它函数调用,则这个函数是复杂的,但如果里面只是有个报错呢

所以 Xray 仅本体开 -l=4 跟默认没区别的原因是,独立函数 80 以内的都是 leaf?

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

大概是因为 Xray 本体代码里的独立函数太少,函数大都附着在结构体上的,所以这个 PR 是内联了依赖里大量 80- 的 leaf 函数

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

@Fangliding 话说文档现在就可以把 domainMatchertype 删了

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

2d023b0 DNS 出站 nonIPQuery 将 "reject" 设为了默认值,第一次用 Codespace 写代码并 commit,以前只用来 force-push

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

文档可以标注一下 domainMatcher 配置项已删,只留了新的域名匹配算法

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

*ray 性能瓶颈的话目前:

  • 入站与出站之间塞了一个 link,如果去掉的话可以减少两个协程以及互拷时的函数调用(即使是 XTLS 非 Splice)
  • 没有预留 header 空间,否则加明文 header 可以少一次拷贝
  • REALITY/TLS 先把数据读到自己库的 buf 导致多了一次 copy(),这个需要改库并把 buf.Size 增加到 16384

不过 XTLS 的话那没事了,这也是为啥这么多年了后两条一直没改,不过 16384 那个快改了,但是对传输层不太友好,得设计一下

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

因为 16384 那个最符合 TLS 的特征,但是如果包个传输层再包个 TLS 呃,需要一大一小两个 data record 才能把数据发出去

@patterniha

This comment was marked as resolved.

@RPRX
Copy link
Member

RPRX commented Aug 16, 2025

Update dns_proxy_test.go

de23e51

@KobeArthurScofield
Copy link
Contributor Author

KobeArthurScofield commented Aug 16, 2025

leaf 函数的问题,Golang 应该是认为如果一个函数里面有其它函数调用,则这个函数是复杂的,但如果里面只是有个报错呢

所以 Xray 仅本体开 -l=4 跟默认没区别的原因是,独立函数 80 以内的都是 leaf?

默认内联给调用函数的定的配额是占用 57 个 AST 节点,除了 panic 之类的
-l=4 把调用函数的配额占用改成了 1 以便把非 leaf 函数也内联了
可能是 *ray 里面本来有这种条件的非 leaf 函数就不多(而且有可能有调用次数也不多),加上各种编译器和链接器的处理之类的最后出来的结果大小几乎没变化(但是内容的确是有变化的)

@KobeArthurScofield
Copy link
Contributor Author

KobeArthurScofield commented Aug 17, 2025

有点不太信邪,编译的时候在 -gcflags 里面加了个 -m 用来查看编译时的内联决策 然而没想到 Go 竟然鸡贼得没法用普通手段把落到 PowerShell 里的输出写进文件

可以确认的是,不在 -gcflags 里面加 all= 的话,-l 的值不管是几都只会对 main 包生效,因为编译目标就是 main 包,其它的包连带依赖统统默认内联。然而 main 包就总共四个文件那点东西,不管怎么调内联大小变化都不明显,经过编译器和链接器的其它处理(包括加 padding 之类的)编译出来的大小变化就已经被抹平了,只看大小当然不怎么看得出来,实际上是有效果,但是仅限 main 包。

加上 all= 之后,调整 -l 的生效范围就是整个代码库连带引入的外部依赖。 理论上可以用加列表的方式来查看仅针对代码库进行处理的效果但是代码库的包实在是太多了以至于没地方写得下 目前以 https://github.com/XTLS/Xray-core/tree/de23e51077d34937229c3997586aaa99634df409 下的 linux/amd64 的效果看:

无内联 默认内联 激进内联(包含非叶子 AST 对象)
26,792,084 (25.55MB, -3.10MB, -10.8%) 30,052,500 (28.66MB, 0MB, 0%) 34,037,908 (32.46MB, +3.80MB, +13.3%)

如果是 windows/amd64 的话变化也是轻微波动但是差不多,只是默认内联和无内联的大小变化差异不到 2KB 因为某些原因没被其它处理抹平。

就是默认 SDK 下面单纯的激进内联效用不是特别明显,尤其是对 AST 对象多的完全无法内联的情况要考虑进去 有作用但不是神油不是抹一下就好了

附注:all=-l=0 以及 -l=0 其实是等效的,但是出来的二进制校验值会不一样,因为这些参数也会被记录在二进制中:
image

@RPRX
Copy link
Member

RPRX commented Aug 17, 2025

可以确认的是,不在 -gcflags 里面加 all= 的话,-l 的值不管是几都只会对 main 包生效,因为编译目标就是 main 包,其它的包连带依赖统统默认内联。

已经无话可说了

@KobeArthurScofield KobeArthurScofield deleted the aggressive-inlining branch August 20, 2025 16:06
@qwerttvv
Copy link

高低加一个GOAMD64=v2也能提升一定的性能啊

或者GOAMD64=v3,GOAMD64=v4都加上,用户自己根据自己的cpu选

@KobeArthurScofield
Copy link
Contributor Author

高低加一个GOAMD64=v2也能提升一定的性能啊

或者GOAMD64=v3,GOAMD64=v4都加上,用户自己根据自己的cpu选

GOAMD64 GOARM64 GOPPC64 GORISCV64 这么几个 而且 GOARM64 是各种意义上最复杂的那个

然后不要高估用户选架构的能力

最后印象中是有说过出来效果差异不大的

@KobeArthurScofield
Copy link
Contributor Author

KobeArthurScofield commented Aug 22, 2025

高低加一个GOAMD64=v2也能提升一定的性能啊
或者GOAMD64=v3,GOAMD64=v4都加上,用户自己根据自己的cpu选

GOAMD64 GOARM64 GOPPC64 GORISCV64 这么几个 而且 GOARM64 是各种意义上最复杂的那个

然后不要高估用户选架构的能力

最后印象中是有说过出来效果差异不大的

GOPPC64GORISC64 各个层级出来的时间不够长不考虑

GOARM64 情况太复杂水太深不考虑

GOAMD64 理论上可以设置成 GOAMD64=v2,实际上有可能不知道谁家好人用着很旧的电脑或者用着很老的处理器做软路由或者别的设备什么的,偏偏这些处理器拉出来对着 x86-64v2 还有可能是漏指令集的,然后:

  • 不留 v1:用户发现用不了,跑来问怎么回事
  • 留 v1 标作 legacy 之类的:用户不觉得自己的处理器是 legacy 下了 v2 的普通包发现用不了跑来问,或者用户处理器 v2 以上只是有点老下了 legacy 然后没有提升,更复杂

再加上加密库在写的时候大概是有针对性优化运行时判断的,加了这个几乎效用不明显

@Fangliding
Copy link
Member

老早就有人说过这几个v1v2v3v4了 我也测过 结果是没有肉眼可见区别
指令集新增的对向量矩阵浮点乱七八糟的优化都不是ray主要的性能开销 主要开销一直都是加解密 在amd64上99%是aes 给aes ni处理的 加多了反而让人不知道选什么到时候日经帖问选哪个 还生怕版本低了自己亏性能

maoxikun pushed a commit to maoxikun/Xray-core that referenced this pull request Aug 23, 2025
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.

6 participants