0%

又来折腾,cgo 内存优化无缘 golang 1.22

前一阵吹水的 cgo 内存优化,也被干掉了,无缘 golang 下一个版本 1.22 …

不过,rsc 大佬说 1.23 会带上,好吧,再耐着性子等个半年吧

原因

rsc 大佬解释说是向后兼容性问题,不过,实际上,并不是这个 cgo 内存优化的补丁,自身有啥兼容性问题

因为这个优化只是新增了两种 #cgo 指令的支持,新增特性一般是没有向后兼容性问题的

而是,因为 golang runtime 中,调用 boring ssl 的 crypto 模块,使用了这两个新 #cgo 指令,然后就导致了 google 内部的测试集跑失败了 …

具体也不知道是啥样的测试集,产生了啥样的错误(之前搞的 cgo CPU 优化,google 内部的测试集就暴露了不少真实的问题)

只有这么个 issue:
https://github.com/golang/go/issues/63739

envoy Go

之前在 Envoy 社区,也有人反馈老版本 go 在跑 go mod vendor 的时候,因为不认识那两个新增的 #cgo 指令,导致 vendor 失败
https://github.com/envoyproxy/envoy/issues/30208

当时我们的解法是,直接把这部分优化给干掉了,想着等 1.22 发布之后再加回来

目前看起来,得等到 1.23 发布了,才能用上这个优化咯

估计 Google 内部的测试失败,也是类似的吧

解决方案

所以,目前 golang 的解法是:

  1. 把 crypto 中使用新 #cgo 指令的优化给 revert 了

  2. 把 cgo 优化给 disable 了,好在还不是 revert

    也就是,语法解析阶段,可以解析新增的 #cgo 指令,不过编译会报错了

期望的效果是,以后 Go 1.22 再跑 go mod vendor 的时候,即使遇到这两个新的 #cgo 指令也不会报错了

但是,Go 1.21 以及之前的,那就不管了

理论上来说,如果只是解决 google 内部测试集失败的问题,也没必要 disable 这个优化,只要 revert 掉 crypto 那个优化就行了

估计是 rsc 觉得,一旦正式提供了这个用法,很多三方库跟进使用这个特性,回头更多用户踩到这个 vendor 的坑,还是会来吐槽 golang 的向后兼容性

哈哈,当然只是我的猜测

彩蛋

最后,我也是才知道 crypto 也用了这个优化,仔细看了下补丁:
https://go-review.googlesource.com/c/go/+/525035

原来,他们对于 cgo 内存优化解决的那个问题(指针传给 C 的 Go 对象总是会被逃逸到堆上)也是心里苦

他们为了少一个对象逃逸,甚至包了一层 C 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
size_t exp_out_len,
const uint8_t *nonce, size_t nonce_len,
const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
size_t out_len;
int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
nonce, nonce_len, in, in_len, ad, ad_len);
if (out_len != exp_out_len) {
return 0;
}
return ok;
};
};

因为原始的 boring 函数,需要返回多个值,除了 ok 之外,还有 out_len 这种指针传参

用了这个优化之后,就可以干掉这种包装 C 函数了,代码可以清爽一些

哈哈,原来 golang runtime 为了性能,也搞这种骚操作 …

只能说,咱们这个优化,还是有点普世价值的 …