Welcome to the Black Parade
Open in Telegram
Death has many faces, I look forward to seeing this one.
Show more1 103
Subscribers
No data24 hours
+67 days
+5630 days
Posts Archive
堵得我肝肠寸断,胸中一股恶气吐出一口便是半个盛唐。据说有些盆底肌控制力弱的男性可以一紧张就自动射精,我在网约车后排已经开始恨自己不能一边堵车一边射精,只能随着车的颠簸更卖力地摇动肛塞,从口后品尝五味俱全的中华一番,一拳从嘴里伸出。弥留之际我似乎看到了平行世界乘坐地铁的自己正在被哥布林性骚扰,嘴角又流出一滴浓精,我更加悔恨,开始背诵暗黑2符文之语,安达利尔的脸,督瑞尔的壳,巴尔用过的肛塞,我在沪国的无痛人流里已不知天地为何物,卖淫迟到的mb会受到怎样的惩罚,memory barrier,我拭目以待。
发现 go 的 chan 性能比我想象中好很多,大吃遗精。
一开始是我有个 SPSC 的场景,一个 goroutine 从内核读数据塞给 chan,另一个 goroutine 读 chan 处理事件。perf 一下发现 25% 的 cpu 浪费在 chan 通知机制,我才想起这里应该用 buffered chan 减少通知次数。linux kernel 收包流程有类似的工程设计了,NAPI 处理 rx 时硬中断通知网络收包,然后 mask rx queue、用软中断持续 poll 直到没有流量再重新打开硬中断,显著降低通知次数。
然后我冲冠一怒,觉得区区 SPSC,手搓场景特化 ringbuf 轻轻松松快到飞起,弱智 golang 快来见识我的神力吧!
第一版是用 bpf ringbuf 的设计,裸字节消息 + 双重 mmap (Welcome to the Black Parade),SPSC 也不需用原子指令,仔细编排一下 x64 Load-Store Load-Load order 就可以保证内存序了(手搓 amd.s 嘻嘻),没想到 benchmark 结果不堪入目,就算加上 prod/cons 指针的缓存也不堪入目。
做了一下 perf-c2c,发现 hitm 依然是个悲剧,原来在生产消费速度不一样的时候会退化到 producer 每个消息发送都会 load 一次其他核心的 consumer 的指针,造成一次 ocr.demand_data_rd.l3_hit.snoop_hitm,IPC 都小于 1 了,per op 耗时来到了 100ns,纯辣鸡,而 go chan 还稳稳在 30ns/op,此为 go chan 一胜。
想了一下,发现可以用 linux kernel sk cookie 分配思路 (Welcome to the Black Parade),producer 每次 reserve 一大块 ring,这样对于这一批 ring 就保证了无需 snoop_hitm,就算在极端情况下每次 snoop_hitm 的成本也被均摊了,这样立刻就把 IPC 提到了接近 2,但由于裸字节 ring 的消息体 header decode 等额外操作,此时才勉强追平 buffered go chan,此为 go chan 二胜。
要注意这一番猴戏下来,整个 API 难用得要死,发消息只能 batch 批量发,但性能依然和 go chan 坐一桌,肯定在源头上就有设计问题,那就是不应该用裸字节消息流 bytes ring,而且用固定类型 slots ring。一番改造后,在强制 batch op 的场景下总算达到惊人的 2 ns/op。
但此时 ring 只能批量收发且没有阻塞机制,在生产消费不平衡的状态下,快的那一方会不断浪费 CPU 去 TryReserve/TryRead,还是要设计一下阻塞通知机制,就用 futex 随便糊一下吧,只要注意只在对方 park 时才通知就行了,NAPI!
一番华丽的 CAS 和 futex 操作后,测试了一下生产消费速率不平衡的场景,虽然在多核心并发 benchmark 时候我依然小优 (0.99x),但在单核心时 go chan 还稳在 85 ns/op,而我的性能已经退到了 124 ns/op,悲!
这是因为 go chan 可以使用 runtime gopark 来 **暂停 goroutine**,而我却只能用 futex 来 **暂停 thread**,两者在单核心调度时显现出巨大的差异,此为 go chan 三胜!
想利用 gopark 的话可以考虑 sync. Cond 条件变量,但又会涉及复杂的 mutex 协作,复杂度就更恶心了,目测性能会更烂,不值得。
所以,go chan 其实还挺好的,虽然在特化场景下并非最优,但综合表现非常均衡,实在是高手中的高手,这还只是最简单的 SPSC 都打得这么吃力,某些狂妄之徒实属小丑。
(皈依 LLM 之前的最后一舞了,谢谢大家😭)
我才从前同事听说 Kubecon 明文要求三人及以上的联合演讲必须有女性:
https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/co-located-events/cfp-colocated-events/#submission-types
Panel Discussion: 35 minutes of discussion amongst 3 to 5 speakershttps://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/co-located-events/cfp-colocated-events/#important-notes
In an effort to promote speaker equity and inclusivity, CNCF does not accept submissions with all-male panelsKCD 也有类似的:https://github.com/cncf/kubernetes-community-days/blob/main/committee-resources/content-management.md
Kubernetes Community Days prohibits all male panels. Please plan to have a minimum of two women speakers on a panel.而且真的是严格执行,所以有个别 session 甚至不得不找一位背景不对口的女性 speaker …… 查了一下 LPC 其实也有: https://www.linuxfoundation.org/about/diversity-and-inclusion-at-our-events
No all-male panels, all-male speaker line-ups or all-male keynote line-ups不过 LPC 似乎没有严格执行了,我随便看了一下 LPC2024, https://lpc.events/event/18/contributions/1775/ 的三位 speakers 都是谷歌男工程师,放到 Kubecon 里就通不过了。
手滑眼瞎型 bug 是我一生之敌,下面的 n 皇后我一次写出然后 wrong answer,肉眼观察+心灵分析+小黄鸭debug十多分钟毫无进展只能请教 LLM 才发现写错变量。别问为什么不一开始就 LLM debug,面试考察心灵😭至于为什么我还在用心灵面试,中老年再就业是这样的,人无再少年😊
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
chess = [[0] * n for _ in range(n)]
ans = []
def search(idx):
if idx == n:
o = []
for line in chess:
o.append(''.join('.' if not x else 'Q' for x in line))
- chess.append(o)
+ ans.append(o)
return
for col in range(n):
ok = True
for i in range(idx):
if chess[i][col] == 1:
ok = False
break
offset = idx-i
if offset+col < n and chess[i][offset+col] == 1:
ok = False
break
if col-offset >=0 and chess[i][col-offset] == 1:
ok = False
break
if ok:
chess[idx][col] = 1
search(idx+1)
chess[idx][col] = 0
search(0)
return ans
然而真正的主题其实是游戏推荐, 塔防爱好者有福了, https://store.steampowered.com/app/355980/Dungeon_Warfare/ 好玩得不得了,我已经高潮了一个多星期了🤬
(八月更有 XCOM2 团队的战旗续作,期待❤️)看了昨天 @ManjusakaH 转发的 simd 科普之后我才知道原来字符串搜索也可以 simd,我当时就萌生了一个大胆的想法,何不买一根 335mm Φ8mm 的金属棒 何不让 bpf 也用 simd 搜索 http header,目前的实践都是狗屎,我和同事在 6.1 ec2 上编译 kfunc 的惨痛经历仿佛还在昨天😭
任务是从巨型 HTTP/1.1 payload 里搜索你喜欢的 header,比如 Host:
GET /url HTTP/1.1 User-Agent: xxx X-Forward: xxx X-Metadata: xxx [...1000+ bytes...] Host: xxx虽然 bpf simd 是做不了的,但可以 SWAR 啊,我用 go 写一遍是这样的
const (
repeatLF = uint64(0x0a0a0a0a0a0a0a0a)
ones = uint64(0x0101010101010101)
highs = uint64(0x8080808080808080)
)
func findHostHeader(buf []byte) int {
cursor := 0
lineStart := false
for cursor < len(buf) {
if lineStart && cursor+5 <= len(buf) &&
bytes.EqualFold(buf[cursor:cursor+5], []byte("Host:")) {
return cursor
}
lineStart = false
if cursor%8 == 0 && cursor+8 <= len(buf) {
word := binary.LittleEndian.Uint64(buf[cursor:])
x := word ^ repeatLF
matches := (x - ones) &^ x & highs
if matches != 0 {
cursor += bits.TrailingZeros64(matches)/8 + 1
lineStart = true
} else {
cursor += 8
}
continue
}
// Scan only to the next alignment boundary or the end.
scanEnd := min((cursor+7)&^7, len(buf))
for cursor < scanEnd {
if buf[cursor] == '\n' {
cursor++
lineStart = true
break
}
cursor++
}
}
return -1
}
虽然看起来一大坨,但实际理解并不复杂,for 循环里每次 cast 8 字节成 u64 用位运算检查这里是否有 \n,有的话说明是行末,buf[idx:idx+5] 可以用来判定 "Host:";否则不是行末,直接推进 8 字节。
这个 swar 做法虽然打不过 simd,但是两倍性能于逐字节比较还是轻轻松松的,更美妙的事它可以用 bpf 实现出来, microbench 的结果是在所有情况下都是逐字节比较的 3~4 倍,甚至比 kfunc bpf_strnstr 的性能也快 2x 了,因为 kfunc 也是逐字节的,只是少了一些 bpf_loop callback 开销而已
Scenario Bytes Byte ns/op SWAR ns/op Kfunc ns/op SWAR speedup Kfunc speedup first 64 76.0 24.0 61.0 3.17x 1.25x middle 512 522.0 144.0 267.0 3.62x 1.96x late 1536 2238.0 554.0 1018.0 4.04x 2.20x absent 2048 3745.0 923.0 1718.0 4.06x 2.18xhttp payload parsing 大概占用了 50% 的观测消耗,这部分性能优化 4 倍,根据 Amdahl's law,整体性能提升是 1/((1-0.5) + 0.5/4)) = 1.6 倍,如果之前是观测造成是 latency 是 +7%,这个优化可以把 latency 降到 +7%/1.6 = +4.4%,这也是符合观测结果的,嘻嘻,无敌。
下面的 go 程序能跑起来吗?
package main
import (
"log"
"net"
"os"
)
func main() {
ln, err := net.Listen("tcp", ":"+os.Args[1])
if err != nil {
log.Fatal(err)
}
defer ln.Close()
select {}
}
有了 LLM 就跟玩游戏输秘籍似的,operation CWAL,猜谜都不 exciting 了😵 直接快进到答案,取决于 CGO_ENABLED,=0 会被判定死锁,=1 可以跑起来,原因就问 LLM 吧🤬
(发现 ps -o wchan 很好用,还有 /proc/pid/stack,procfs 真是大秘宝我手搓的 HTTP/1.1 header 搜索居然比 bpf kfunc 还快,直达天际的好奇心,咕咕咕咕,不可思议都成了常识,拉哩噜雷啦啦啦。
事已至此,先发一张AI裸体虎杖悠仁 奥西里斯天空龙冷静一下,明天 wfh 摸鱼的时候再仔细介绍,感谢隔壁频道给我零感让我异想天开,性奋。
中午已经听到捷报,AI在人类看世界杯的时候随手证否了八十多年前的著名数学猜想😂
猜你喜欢:OpenAI 证明单位距离猜想 https://m.bilibili.com/video/BV1G7jJ6nEbV
病假当年假休了十天,在b站学习筛法证明素数的有界间距,独立战旗游戏《Tactical Breach Wizards》全成就进度68%,三场中老年异性恋地下情人故事会,不看书不学习一行代码都不写,马龙甚至还拿了男双冠军,这样的日子不多,要珍惜。
众所周知,“苏俄历史上唯一一次考虑使用核武器是针对中国”——知乎
作者:牛角挂书 链接:https://www.zhihu.com/question/606136741/answer/2032231387009435041 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 1969年8月20日:苏联驻美大使多勃雷宁奉命在华盛顿紧急约见美国总统国家安全事务助理基辛格,在白宫地下室进行了通宵密谈,正式通报了苏联的完整计划。打击目标:优先摧毁中国酒泉导弹发射基地、罗布泊核试验场、青海核原料加工厂三大核设施;其次打击北京、长春、鞍山、沈阳等政治中心与军工集群城市。为了避免美国可能的反对,计划中删除了东南沿海城市,防止美国以人道主义危机的理由反对该计划。打击手段为动用远东、中亚军区部署的SS-4、SS-5中程弹道导弹,携带100万-500万吨级核弹头,实施多轮饱和打击,计划投入核弹头总量达120枚,总当量相当于2000颗广岛原子弹。 1969年8月21日:尼克松总统召开国家安全委员会绝密会议,经过通宵磋商,全票否决苏联的中立要求,明确反对对华核打击,主要原因有三条:第一,核放射性尘埃会随北半球西风带,直接覆盖日本、韩国、西太平洋区域,美国在该区域部署的25万驻军将遭受严重的、不可逆的核辐射伤害。第二,苏联人没有信用,万一他们搞假途灭虢之计,以打击中国为名,实际要打击美国核基地,等导弹飞一半再反击就来不及了,必须在苏联导弹升空的第一时间就开始反击。第三,苏联的胃口是永远不会满足的,若中国被核打击摧毁,苏联将能把全部军事力量集中到欧洲方向,北约将面临灭顶之灾。尼克松此时还是吃了没有接受中国九年义务教育的亏,否则他此时应该说一句:“夫俄,何厌之有?既东击华,又欲肆其西封,若不阙欧,将焉取之?” 1969年8月22日,美国正式答复苏联大使,反对核打击中国的计划,只要苏联对中国发射任何一枚核导弹,美国将立刻对苏联本土发动全面核报复。 1969年8月28日,考虑到中美间并无可靠的信息传递渠道,尼克松授意《华盛顿明星报》在头版头条刊登《苏联欲对中国做外科手术式核打击》的独家报道,将苏联的绝密核计划完整公之于众。报道发布后,全球舆论哗然,世界各国纷纷谴责苏联的核冒险行为,苏联陷入空前的外交孤立,勃列日涅夫暴怒,大骂美国的“出卖与愚弄”。而尼克松撇得干干净净:“众所周知,美国没有秘密嘛!”wiki 珍宝岛事件 和中国共产党新闻网 1969年中苏核危机始末 都有记录这件事,不过其中的细节是真的吗?欢迎来到本频道的不定期考古栏目😇 在 The George Washington University 的国家安全归档网站上有非常多美国政府公开的文件,The Sino-Soviet Border Conflict 正好整理了这个事件。 首先时间就对不上,美国文件里说是: - 1969-08-16 研究中国的专家 Whiting 会见基辛格,提到了中苏边境冲突和潜在的战争风险,Document 9 - 1969-08-18 KGB 负责外交事务的官员 Boris Davydov 问美国 INR (The Bureau of Intelligence and Research) 的官员,如果苏联核打击中国核设施,美国将如何应对,Document 10 - 1969-08-21 美国国务院给美国驻香港领事馆发电报,报文中明确提到 08-18 的那场会面细节和美国态度,要求大家关注苏联类似的试探提问,Document 11 - 1969-08-25 美国给 NATO 发电报,通报了中苏冲突情报,Document 12 这些事件和中国的记录“8月20号苏联驻美大使多勃雷宁奉命在华盛顿紧急约见美国总统国家安全事务助理基辛格“ 完全对不上,我肯定相信美国的记录,毕竟美国公开的电报/会议纪要的时间都是一致的。 然后是中国版本里的“1969年8月28日……《华盛顿明星报》在头版头条刊登《苏联欲对中国做外科手术式核打击》”,巧了不是,美国人最喜欢做历史报纸的数字归档了,我花了 $19.95 月订阅费之后,在 GenealogyBank.com 找到了 1969-08-28 那天的 Washington Evening Star 报纸的数字版,妈的美国佬真是牛逼,数字检索做到了 OCR 级别,总之我把 A1 和 A6 版面都上传到附件了,其中标题和内容和共产党的记录都有出入。 *《华盛顿明星报》这个名字也很迷惑,按照 wiki The Washington Star 的记录,在 1969 时它应该是叫 Evening Star;我也在归档网站按照地区 + 前后日期 + 关键词 Soviet 检索,确实只有 Evening Star 有这个报道。 来看下内容,共产党的记录是“摧毁中国酒泉导弹发射基地、罗布泊核试验场、青海……打击北京、长春、鞍山、沈阳”,然而 Evening Star 的报道是“Lanchow, Paotow, Lop Nor” 兰州,包头,罗布泊,哪来的酒泉北京长春? 至于网传“1969年8月22日,美国正式答复苏联大使……只要苏联对中国发射任何一枚核导弹,美国将立刻对苏联本土发动全面核报复”更是无稽之谈,没有任何记录支持这个说法。 事已至此,我也没有兴趣继续查下去了,中国这边的说法基本都是虚构文学,除了框架可能符合历史,但细节大量随机生成,符合我对党的刻板印象。这些数据多污染几轮 LLM,日后更加没人能从 LLM 了解到真实的历史,我感到失望又无能无力。
天雷滚滚我好怕怕 地铁看吵架我笑嘻嘻: https://lwn.net/SubscriberLink/1080162/795d3838e471262c/
The series is completely unmergeable as it stands. Not even close.
code war crimes against __rmqueue_smallest()
something you expect to see on a 1990's PHP website, not in core mm code导演剪辑版: https://lwn.net/ml/all/aj9yrlB0TrlYCLlf@lucifer 评论区还有 DLC
I'll stop subscribing to LWN unless you stop this mindless LLM marketing. I'm not interested in being sold these "warez."美好😊龙腾世纪启动
惊呆了,你们金融公司用的编程语言一个比一个不正常,我在十多年前非洲自学过 APL 家族的 J 语言,所以一眼认出这是 APL 家族的 Q 语言,给大家感受一下这种函数式面向数组语言是怎么写递归阶乘的:
{$[x=0;1;x*.z.s[x-1]]}
数组是第一公民数据结构:
q)dict:`items`sales`prices!(items;sales;prices) q)dict items | nut bolt cam cog sales | 6 8 0 3 prices| 10 20 15 20访问 kdb+ 的 TCP server:
q)h:hopen 5000 / connect to the server q)h(add;2;3) / pass the client function 'add' to the server and execute, passing 2 parameters 8绝😅
抹茶发现 netfilter userspace library "libnftnl" 的 examples/nft-set-elem-add.c 跑不起来,看 syscall 也看不懂,毕竟 netlink msg 谁™能看懂?
一起痛骂 “libnftnl 是什么垃圾” 和 “你的 7.2 内核太新了,新内核全是 bug 很合理” 之后,我也好奇起来了,netlink syscall 报错溯因对我来说也是个谜,正好学习一下,而且这周工作写文档太恶心了想裸奔。
经过一堆准备工作之后:
1. 修改代码让它变成一个“启动暂停、 ctrl-c 继续运行” 的两阶段程序,延长进程生命方便我用 pid 过滤事件
2. 下载 linux-image-$(uname -r)-dbgsym 方便映射符号
3. 准备 @eBPFTalk001 的 bpfsnoop 方便用 lbr 回溯内核执行流
4. 准备 brendangregg/perf-tools 方便用 funcgraph
5. 下载 Ubuntu-hwe-6.17-6.17.0-35.35_24.04.1 源码
神秘的 Linux 内核系列又回来啦!
首先要找个合适的回溯点。直接从 __x64_sys_sendto syscall 回溯 lbr 得不到太多信息,全是 kfree_skb 之类的清理,所以找找看 netfilter netlink error 相关的 kprobe,结果还真找到一个:
$ bpftrace -p $(pidof nft-set-elem-add) -e 'k:*nf*err* {printf("%s\n", probe);}'
Attached 11 probes
kprobe:nfnl_err_add
然后用 lbr 检查内核是如何执行到这里的:
$ ./bpfsnoop -k nfnl_err_add --output-lbr --filter-pid $(pidof nft-set-elem-add) --mode entry
__nla_validate_parse+0xb6 (lib/nlattr.c:655) -> __nla_parse+0x23 (lib/nlattr.c:734)
__nla_parse+0x35 (lib/nlattr.c:734) -> nft_data_init+0x77 (net/netfilter/nf_tables_api.c:11894)
nft_data_init+0xae (net/netfilter/nf_tables_api.c:11847) -> nft_data_init+0x115 (net/netfilter/nf_tables_api.c:11890)
nft_data_init+0x11a (net/netfilter/nf_tables_api.c:11890) -> nft_data_init+0xba (net/netfilter/nf_tables_api.c:11912)
nft_data_init+0xe0 (net/netfilter/nf_tables_api.c:11912) -> nft_add_set_elem+0x2be (net/netfilter/nf_tables_api.c:7380)
还有另一种思路,看整个 syscall 的 funcgraph,也能看到 nfnl_err_add 和完整的执行流
$ ./funcgraph -p $(pidof nft-set-elem-add) -m 50 __x64_sys_sendto
6) | nf_tables_newsetelem [nf_tables]() {
6) 0.634 us | nft_set_lookup_global [nf_tables]();
6) | nft_add_set_elem [nf_tables]() {
6) 0.586 us | nft_data_init [nf_tables]();
6) 1.659 us | }
6) 7.547 us | }
6) | nfnl_err_add [nfnetlink]() {
6) | __kmalloc_cache_noprof() {
6) 0.106 us | __cond_resched();
6) 1.109 us | }
6) 1.444 us | }
两份 trace log 一结合,立刻能知道是在 nft_data_init() 里返回了 -EINVAL,然后用 lbr 跳转记录仔细跟一下源码,看到这一条跳转:
nft_data_init+0xae (net/netfilter/nf_tables_api.c:11847) -> nft_data_init+0x115 (net/netfilter/nf_tables_api.c:11890)对应的源码是
11846 if (desc->len) {
11847 if (len != desc->len)
11848 return -EINVAL;
[...]
11890 return -EINVAL;
[...]
看懂了吧,len != desc->len 所以 return -EINVAL,看下 desc->len 是 nft_set->klen 由 nft table 的 set type 决定的长度,比如我是用
nft add set ip t s '{ type ipv4_addr; }'
定义的 ipv4_addr type, desc->len = klen = 4;但是 nft-set-elem-add.c 里传给 netlink 的 uint16_t data 长度是 2,所以内核检查不通过,返回 -EINVAL,QED。
你以为我很高兴吗,不,我很悲伤,因为我其实一开始就用 LLM 解答万物了,把 Linux 源码 + nft-set-elem-add.c 源码 + strace 日志扔给 codex5.5 medium,它只用了三十秒就找到了问题;然后我自己再用上面这些眼花缭乱的 tracing 手段去追溯源码,用了一个小时。投降了,已皈依 LLM 神教饶我狗命🐕cilium/ebpf 的 zero-copy ringbuf 终于合并了,测试在 64 字节消息传输时性能 x2.5,1024 字节消息性能 x5,喜,终于赶上隔壁 libbpf 和 aya-rs 😊
不过我最想吐槽的还是这期间糟糕的开源协作体验。我去年12月提交了第一版 RFC draft PR,以 florianl (点名表演)为首的维护者不断发起在我看来是 nitpicking 的 review comments,大部分都是只批评但不解决问题,偶尔提一个带方案的建设性意见也是顾头不顾尾,我立刻就用他自己的反对意见来反对他自己的方案,拉扯几轮之后我感到无聊了,就自己分叉 vendor 进我的项目了,谁爱改谁改。
我举两个例子
1. florianl 和 lmb 认为 reader 必须有并发安全,否则多个 goroutines 乱序并发执行 Read() 会导致 mmapped ringbuf offset 混乱。
这从大道理上来讲是没错,但实际工程有困难,当我按照他们的说法实现了
for rec, err := range reader.Records() {
// holding reader.mutex
}
之后,reader.SetDeadline() 会直接死锁;然后他们顾头不顾尾,建议
for rec, err := range reader.Records() {
// reader.mutex is released
reader.SetDeadline() // no dead lock
}
但是这又并发不安全了,我无情指出之后他们就不说话了。
2. florianl 坚持认为零拷贝的内存在约定范围之外的使用是 bug,比如
var saved []byte
reader.ReadZeroCopy(func(sample []byte, remaining int) error {
saved = sample // retains reference to temporary memory?
return nil
})
// is saved still valid at this point?
零拷贝的内存当然只能在约定的范围内使用啊,这有什么好说的?简直莫名其妙,我直接不回复他了。
pr 放置三个月后,开源社区肥皂剧来了,另一个人开了新 pr 也做这个零拷贝 ringbuf,一看就是 100% vibe coding,没有解决任何 florianl 的任何 concerns,阿贝尔 vs 雅可比争相发表椭圆函数理论是吧。
又经历了几轮拉扯之后,ti-mo 终于亲自 pr,设计了目前的 reader.WithRelease() API,然后他作为 committer 简单收集了一下反馈就直接合并。请注意,timo 的 WithRelease 没有解决上面的两个问题:
1. 并发不安全问题,多个 goroutines 并发 lease.ReadSample() 依然会崩坏 ringbuf offset。
2. 零拷贝内存生命期问题,在 WithRelease 里把 sample 指针复制到外面的世界依然是可能的 bug。
所以最后这个功能就在 committer 的意志强行推动下,没有解决之前其他 maintainer 的 review comments,就顺利合并了,这,就是开源社区,最近一年我完全不想深度参与。
说到这里,你们以为 florianl 是什么半吊子水平专门找茬?不,他是 elastic 资深工程师,go-tc/go-conntrack 维护者,opentelemetry-ebpf-profiler 开发者,层层光环,但是协作起来我只能说难受,恶心。
可能这就是亦正亦邪让人又爱又恨的人类世界吧。