TGINSIGHT CHAT
Welcome to the Black Parade
@TheB1ackParade
MusicDeath has many faces, I look forward to seeing this one.
Recent posts
Page 5 of 76 · 907 posts
Posted Dec 24
Seasonal felicitations to you all😋 —— Sir Humphrey Appleby
Posted Dec 23
啥玩意儿,我都离职八个月了,思科还在给我发工资?不会过一会儿电话打来让我退回去吧 😀
Posted Dec 22
qq空间提醒我十年前的今天我入职了第一份程序员工作😂 我很幸运,在很年轻时就找到了自己能够快乐一生的职业,不敢笑傲五洲也不愁天地悠悠,只是狂歌一曲,恍惚间就化入无穷😄
Posted Dec 19
终于检查完这篇文章了: https://skoredin.pro/blog/golang/cpu-cache-friendly-go TLDR,AI 文可能性很大,正确内容里夹着部分错误,误导性高,但具有启发性,需读者花时间检查错误和内化。 那我就不要脸地带大家读一遍吧😋 False Sharing: The Silent Killer 这第一小节就给我这种非科班出身一个震撼,怀着巨大好奇让 AI 写 benchmark 又发现测不出差距转而痛骂 AI,但其实文章是对的,在多核 lock prefix insn 并行执行下 false sharing 真的可能导致六倍性能差距,见评论区 https://t.me/danteslimbo/5575 Measure Cache Misses (Linux) 我的评价是不如直接 perf stat -d 啥都有;此外 false sharing 在 TopdownL4 里。 Data-Oriented Design: Array of Structs vs Struct of Arrays 这是对的,也比较好理解。 Prefetching: Help the CPU Predict 这是对的,尤其要注意最后那个线性迭代本身就已经有 cpu prefetch,但在线性迭代里手动 prefetch 下一个 cacheline 依然能让性能 +25% func SumLinearWithManualPrefetch(data []int, prefetchDistance int) int { sum := 0 for i := 0; i < len(data); i++ { j := i + prefetchDistance if j < len(data) { _ = data[j] } sum += data[i] } return sum } QC 前几天分享了一篇文章测试了 Go 程序迭代模式对 prefetch 的影响: https://lemire.me/blog/2025/08/15/predictable-memory-accesses-are-much-faster/ 其中最令我印象深刻的结论是 bouncing access (读 a[i] 和 a[len-i] 一头一尾弹跳式非线性读)居然能有最好的性能,原因是指令级并行,我已有 perf 验证。 Hot/Cold Data Splitting 是对的,容易理解。 NUMA-Aware Allocation 没有条件测试🤬下一题 Branch Prediction Friendly Code 这是错的,错得非常彻底,因为 Go (1.22 ~ 1.24) 会把 if v > 128 { count++ } 编译成为无分支跳转的指令 0x000000000049fe33 <+19>: inc %rcx 0x000000000049fe36 <+22>: cmp $0x80,%rsi 0x000000000049fe3d <+29>: cmovg %rdi,%rdx cmovg (条件 move) 保证了原文里 CountCondition 函数在有序或者无序输入下的分支预测错误率是一样低的。 Cache-Conscious Hash Table 居然是对的。RobinHoodMap Set 性能不行,但是 Get 指令可以达到 go map 的五倍性能,在小 value 的时候往后检查一个 cacheline 的 distance 性能真的很炸裂。 SIMD-Friendly Layouts 错误的,里面两个观点都是错的: 1. Padding for 16-byte alignment 可以让编译器编译出 SIMD 指令。实际上不需要 pad 也是 SIMD 指令,而且 pad 之后影响了 cache miss rate 导致性能下降。 2. _ [0]byte 可以强制结构体对齐 cacheline。错误的,随便测一下就知道是错的。 其实我觉得 cache friendly 还只是高性能 CPU 程序的冰山一角,我今年学到的 CPU 指令级并发 (tma_ports_utilized_3m) 才是最黑魔法的,比如浮点乘法 sum = sum * (b[i] * c[i]) vs sum = sum * b[i] * c[i] 前者比后者快了 1.5 倍 (0.842 vs 1.345 ns/elem),这些都是 x64 特供魔法,非常有趣。 大部分内容都是年轻聪明的 QC 老师教我的,请大家多多关注他的频道: https://t.me/QC_Grove BTW, https://uica.uops.info/ 503 Service Unavailable,悲!
Posted Dec 18
48+10+7+6+5=76,剩下那 24% 的游玩时间其实也是我珍贵感动的经历啊,包括: - 辐射4 - 银河护卫队 - 宇宙巡航机:起源 - 往事伴我(With My Past) - 动物井 - 植物大战僵尸1 - 递归(Recursed) 全年游玩时长:807 hrs,太自🌟自弃了 😀 让我看看谁比我更长🤬
Posted Dec 14
因为不打算续 RoamResearch 了(我居然订阅了五年这么昂贵的笔记服务? 🥴),在仔细阅读和思考自己四五年前写得乱七八糟的玩意儿,发现虽然大部分很幼齿,但还是有少部分是有启发性的😂打算精炼一部分自己重新思考后的笔记,以合订本的形式集中放送。 以上只是我在意淫,事实是我已经开始年末的 steam binge 了,《巫师3:狂猎》 预备开始。 😀
Posted Dec 14
去年被 ibug 感谢了今天才发现(这种阴暗爬行的风格有点像我,相反面就是伊洪那种大开大合的性格“我在这里感谢了你请查收谢谢”) https://ibug.io/blog/2024/08/first-touch-bpftrace/ 其他的我看不懂,但他说这个 bpftrace 跑不起来我就来劲了 #include <linux/socket.h> #include <net/netfilter/nf_conntrack.h> kprobe:nf_ct_delete { // The first argument is the struct nf_conn $ct = (struct nf_conn *)arg0; // Check if the connection is for IPv4 if ($ct->tuplehash[0].tuple.src.l3num == AF_INET) { $src_ip = $ct->tuplehash[0].tuple.src.u3.ip; $dst_ip = $ct->tuplehash[0].tuple.dst.u3.ip; printf("Conntrack destroyed (IPv4): src=%s dst=%s\n", ntop($src_ip), ntop($dst_ip)); } } 我试了一下最新版的 0.24 虽然报错不同但依然解不出 $dst_ip。其实这种依赖 BTF 自动计算偏移解引用如果有问题的话就改成手动解引用,零难度,就是可读性差一点。 比如我们要读 $ct->tuplehash[0].tuple.dst.u3.ip ,那就依次检查一下这些结构体字段的偏移: ~ $ pahole -C nf_conn | grep tuplehash struct nf_conntrack_tuple_hash tuplehash[2]; /* 16 112 */ ~ $ pahole -C nf_conntrack_tuple_hash | grep tuple struct nf_conntrack_tuple tuple; /* 16 40 */ ~ $ pahole -C nf_conntrack_tuple | grep u3 union nf_inet_addr u3; /* 20 16 */ ~ $ pahole -C nf_inet_addr | grep ip __be32 ip; /* 0 4 */ 然后从 $ct 指针手动偏移再 deref 就可以了 $dst_ip = *(uint32*)((uint8*)$ct + 16 + 16 + 20 + 0); 然后就可以运行了 $ sudo bpftrace ct_del.bt Conntrack destroyed (IPv4): src=127.0.0.1 dst=127.0.0.53 ^C
Posted Dec 13
这是 BoLi 这周二提出的问题,他问我 RFS 在现代内核上真的有用吗。 RPS 的核心思想是在 GRO 之后、进入协议栈之前做一次软件的 CPU 负载重分配,把本来在 CPU 0 上的 skb 扔给其他 CPU;RFS 更进一步,说既然都在重新分配 skb 给 CPU 了,那我们不如直接扔给收包进程所在的 CPU,这样符合菊部性原理,能够更好利用 CPU cache。 https://docs.kernel.org/networking/scaling.html#rfs-receive-flow-steering 这咋一听好像合理,但仔细推敲可能会有很多问号,好工程师的直觉简直无敌啊,我怎么就没有这种直觉🤬 我画了一份 payload 数据视角的收包流程图,忽略了中断,特化为 tcp 收包,希望没有严重的事实性错误,如果有请斧正🙏 其中最重要的是三个加粗的 CPU copy,第一次是 DMA 拷贝,不消耗 CPU,所以不会产生 CPU cache;第二次是 build skb,在现代 NIC 上如 mlx5 都是零拷贝,直接让 skb->data 指向 packet va,所以也不会产生 CPU cache;第三次是用户态调用 syscall 才会触发真正的数据拷贝,由于之前 CPU 从没有拷贝过 payload,所以这一步无论在哪个 CPU 执行都无所谓,反正都没有 cache。 上面的第二步 build skb 需要特别说明,因为在 archurchiao 的权威指南里 (https://arthurchiao.art/blog/linux-net-stack-implementation-rx-zh/#%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%95%B0%E6%8D%AE%E5%A4%8D%E5%88%B6) 把这一步称为“第二次数据拷贝”,然而我仔细看了一下 6.14 内核的 mlx5e_skb_from_cqe_linear -> mlx5e_build_linear_skb -> napi_build_skb -> ...,应该就是零拷贝的。 Archurchiao 是非常强悍的工程师,在荷兰人 Dylan Reimerink 的 docs.ebpf.io 公开之前,Auchurchiao 在 bpf、现代内核网络方面的博客甚至会让 google.ch (瑞士谷歌)收录他的中文博客。不过内核实在过于复杂,实在难以 100% 把握全部细节。 第二部 build skb 还需要另外说明,这一步是否零拷贝是网卡驱动的实现,比如在 qemu 虚拟机的 virtio interface 的实现里,就是用 GOOD_COPY_LEN (128) 来做分水岭:如果 > GOOD_COPY_LEN,零拷贝构造 skb;否则小包直接拷贝构造: https://elixir.bootlin.com/linux/v6.14/source/drivers/net/virtio_net.c#L861 让我们回到最初的问题,如果构造 skb 是零拷贝,那么 RFS 把 skb 重分配给接收进程所在的 CPU 还有用吗?我严重怀疑一点用都没有,反而由于重定向的软中断导致用户态进程被中断干扰、CPU cache 命中下降。 我尝试着做了一些实验,但都不太成功🤬 高性能网络测试很复杂,我妄图通过本机 ubuntu desktop + qemu 搭建测试环境,但不管怎么绑核、绑 irq、隔离、驱逐干扰,测试结果都波动很大,构不成可信结论。看来还是要搞 homolab 呢🤯如果有高性能网络专家有相关知识和经验,请交交我😊
Posted Dec 12
lpc 这个 session 简直群星荟萃,里面随便找个名字搜一下都会有惊人的履历,比如 ftrace 的发明人 Steve Rostedt 担心 AI 引用的代码有法律问题,Linus 亲自把话题从 AI coding 扭转到 AI review,bpf 创始人 Alexei 吹爆 bpf 子系统和 meta 用 AI review 的体验,io_uring 发明人 Jens Axboe 表示同意,“a maintainer of last resort” Andrew Morton 也有 "stunning" 的 AI review 经历。 Starovoitov said that he loves the reviews that the BPF community gets from the LLM systems. They ask good questions even when the reviews are wrong. Even better, developers respond to the questions, despite the fact that they are answering a bot; those answers can be used to help the models learn to do better in the future. 而我,还在虚拟机里运行 codex --dangerously-bypass-approvals-and-sandbox --search (zzh 教我的 🙏) ,完全没有体会到 AI review 的精妙之处,我自我感觉还好极了,脑子全是粉红的恋爱泡泡。。。 https://lwn.net/SubscriberLink/1049830/c0f287d050ee0e8a/
Posted Dec 12
《时空幻境》、《见证者》 ➡️ 《沉星之序》 https://store.steampowered.com/app/499170/Order_of_the_Sinking_Star/ 《神界原罪2》、《博德之门3》 ➡️ 《神界》 https://divinity.com/zh-CN 好好好,我先贷款全成就了🤬🤬🤬
Posted Dec 8
刚交的朋友、内核开发者、 MM - THP reviewer、热情浩克的 Lance Yang 在 tg 开频道啦(我一个字都看不懂),欢迎抹茶、梓瑶、(阴暗爬行的)silsrc、等各位职业选手(以及像我这种纯打酱油的爱好者们)订阅频道,限时开放订阅中(🤬 https://t.me/k77777777777k Lance Yang 在内核的工作一览(我一个字都看不懂): https://lore.kernel.org/linux-mm/?q=Lance+Yang (我为什么刚才用的 netdev link... )
Posted Dec 6
最近一直在优化公司观测性项目的性能,真好玩😋(我有个很烂的理论:上班的本质是坏的,但是工作需求使我有动力去思考之前忽视的问题,反而又执行好了🤬) 其中最有趣的一个发现是 bpf ringbuf。 我在绞尽 pre-cum 想办法降低 bpf kern -> user 的性能开销时,我发现 cilium/ebpf 的 ringbuf Read/ReadInto 居然不是零拷贝?那 ringbuf reserve 本身的零拷贝优势直接原地消失了,这么多年居然无人发现。于是 PR 走起,在 1024 字节的 big record 的情况下性能乘以四: https://github.com/cilium/ebpf/pull/1915 虽然比利时人看起来不太想合并的样子,我无所谓,反正我已经通过读私有指针 hack 进自己的项目了,我自己爽到就行( (零拷贝同步是这样的,隔壁 splice 都因此烂掉了: https://lwn.net/Articles/923237/ (零拷贝 zero copy 在内核里常常被缩写为 zc,物理世界的朋友知道 zc 于我是什么意思😋以后请叫我零拷贝,谢谢。 顺便看了一下 rust 版本的 aya-rs/aya,发现它们的 ringbuf next() (居然 😀)是零拷贝,而且得益于生命期管理,在 Drop 时自动 consume,雅!这一波 aya 完爆 c/ebpf ... bpf ringbuf 本身的实现也非常有意思,它把一个 page 两次 map 到连续的虚拟内存,这样在第一区域任意读线性内存就能自动折回来,雅!我知道是很古老的技巧了,对不起我太没见识了😭我亲自画了一张示意图,应该还是很容易理解的。。。