QC 的小树林
311 subscribers
163 photos
17 videos
3 files
578 links
Github: github.com/QuarticCat
Blog: blog.quarticcat.com

分享 / 吐槽 / 存档

欢迎来附属群组聊天
Download Telegram
抽时间把 Detypify 重构了一下,发了个版

符号更多了,准确率更高了,页面更丝滑了

@fxck_durov 做的新模型,前三个候选项的 acc 是 99%

Typst 用户可以上 detypify.quarticcat.com 玩玩
👍7
学会了 spinlock 的正确写法,加一个 while (*xp == 1) 的内部 spin 原地提速 30%👍

--- a/bad.c
+++ b/good.c
@@ -34,8 +34,10 @@ static inline int read_once(const xchglock_t *p)

static inline void xchg_lock(xchglock_t *xp)
{
- while (xchg(xp, 1) == 1)
- ;
+ while (xchg(xp, 1) == 1) {
+ while (read_once(xp) == 1)
+ ;
+ }
}


原因是 cacheline bouncing,perf c2c 检查可知好版本的 HITM 只有坏版本的 1/5。太高级了。

ref: perfbook 7.3.1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51
麻薯生日快乐🎂
🥰9🎉1
QC 的小树林
https://github.com/envidera/zench
rust 官方的 #[bench] 什么时候才会出来
🔥1
少数派sspai
Type-C 接口最大的问题,是看起来已经「统一」了 [by 流歌] https://sspai.com/post/108325
才知道还有 5.1K 转接头这种好东西,可以把家里廉价小家电的充电线扔了
Forwarded from Lancern's Treasure Chest
https://isocpp.org//blog/2026/04/announcement-cppreference.com-update

cppreference 挂了一年多,标准委员会老头坐不住亲自下场帮忙了,预计于本月晚些时候将完成全部更新并重新上线。
2
perf 有一个子命令 annotate 很好用,如果之前没有用过的话可以看一下用它 debug cpython [1] 和找数据结构的热点字段 [2]。但可能有人不知道,perf annotate 的结果可能是“错误的”。

考虑下面的代码:
#include <stdint.h>
#include <stdio.h>

__attribute__((noinline))
uint64_t hot_div(uint64_t iters) {
uint64_t a = 0x123456789abcdefULL;
uint64_t b = 7;
uint64_t acc = 0;

for (uint64_t i = 0; i < iters; i++) {
asm volatile(
"xor %%rdx, %%rdx\n\t"
"idivq %[b]\n\t"
"add %%rax, %[acc]\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
: "+a"(a), [acc]"+r"(acc)
: [b]"r"(b)
: "rdx", "cc");
a += 0x9e3779b97f4a7c15ULL;
}
return acc;
}

int main(void) {
volatile uint64_t x = hot_div(400000000ULL);
printf("%llu\n", (unsigned long long)x);
return 0;
}


idivq 指令应该是最慢的热点,我们预期 perf record + perf annotate 的输出应该指向这个这个指令,在 x64 linux6.17 上运行命令试试:
gcc main.c
perf record -e cycles:u -- taskset -c 2 ./a.out
perf annotate --stdio -l -s hot_div


输出却是 62% 的 add 和 0% 的 idiv?
   16.63 :   401165: xor    %rdx,%rdx // a.out[401165]
0.00 : 401168: idiv %rsi
62.06 : 40116b: add %rax,%rcx // a.out[40116b]


我是这样肤浅地理解这个问题的,cpu 执行指令需要 decode 同时推进 rip 寄存器,所以如果 cpu 在执行一句指令,此时 rip 其实指向下一条指令;此事在 call 指令上也很明显,压到栈上的 ra (LR) 其实是指向 call 的下一条指令,本质也是因为执行 call 指令的时候 rip 已经指向下一条。

所以对于上面的 perf annotate 输出,真正的热点其实是 62% 的上一条,idiv 指令。

然而真实世界比这更加复杂。我们在相同的 x64 linux6.17 再试一次:

# perf record -- taskset -c 2 ./a.out 
# perf annotate --stdio -l -s hot_div

4.20 : 401162: mov %rdx,%rcx // a.out[401162]
0.00 : 401165: xor %rdx,%rdx
70.35 : 401168: idiv %rsi // a.out[401168]
0.00 : 40116b: add %rax,%rcx


这次 perf annotate 又准确地指向了 idiv 热点 (70%),为什么?

简单来说 x64 的 perf 在内核里实现了一个叫做 precise_ip 的东西,上面两次 perf record 的微小参数差异导致调用的 perf_event_open syscall 的参数有差异,第一个命令的 precise_ip=3,第二个的 precise_ip=0。如果 precise_ip=3,在内核里会对 rip 做一次修正,这在 intel 里叫做 PEBS (Precise Event-Based Sampling)。这项功能的 fixup 做得非常精细,考虑到上一个指令其实可能是 goto 跳过来到当前 rip 的, intel cpu 通过查询 LBR 准确地回溯到上一次跳转来修正 rip,非常炫。

不过实际使用的时候并不需要观测 syscall 参数,而是通过 perf evlist 直接看采样文件就能知道是否启动了 precise_ip 修正:
perf evlist -v -i perf.data

如果输出里有 "precise_ip: 3",说明采样结果已修正;如果没有 precise_ip,说明有 off-by-one。

以上只针对 x64 的情况,如果是 arm64 又会怎样呢?

不知,没有 arm64 的机器,但 gpt-5.3-codex-medium 说 arm64 有个 SPE 的功能可以在 report/annotate 的时候做矫正。听不懂😋

总之用 perf 要小心了,如果不理解这些实现细节小心得出完全错误的 profiling 结论😉

[1] debug cpython https://t.iss.one/c/1459082815/900
[2] 找数据结构的热点字段 https://t.iss.one/c/1459082815/1015
👍32