第一章:CPU信息查看——知己知彼,百战不殆
做CPU亲和性绑定,第一步是什么?
不是写代码,不是配参数。而是——搞清楚你的CPU到底长什么样。
我见过太多人,上来就绑核,结果绑到了超线程的兄弟核上,性能反而下降。嗯,这种坑我踩过不止一次。所以今天咱们先花点时间,把CPU的家底摸清楚。
1.1 lscpu——三秒摸清CPU家底
我个人习惯,登录一台新机器,第一件事就是敲lscpu。这命令就像CPU的身份证,信息全、格式清。
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 32
On-line CPU(s) list: 0-31
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Model name: Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz
Stepping: 7
CPU MHz: 3000.000
CPU max MHz: 4000.0000
CPU min MHz: 1200.0000
BogoMIPS: 6000.00
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 36608K
NUMA node0 CPU(s): 0-7,16-23
NUMA node1 CPU(s): 8-15,24-31
这里有几个关键字段,做量化交易系统必须盯死:
| 字段 | 含义 | 为什么重要 |
|---|---|---|
| CPU(s) | 逻辑CPU总数 | 决定你能绑多少个线程 |
| Thread(s) per core | 每核心线程数 | 2就是开了超线程,小心假核 |
| Core(s) per socket | 每颗CPU的物理核心数 | 真正的并行计算单元 |
| Socket(s) | 物理CPU颗数 | 跨Socket访问内存延迟高 |
| NUMA node(s) | NUMA节点数 | 交易系统必须考虑NUMA |
| NUMA node0 CPU(s) | 节点0包含的CPU列表 | 绑核时尽量绑在同一节点 |
核心结论:量化交易系统的收报线程、风控线程、交易线程,最好绑在同一个NUMA节点上。跨节点访问内存,延迟可能增加30%-50%。
1.2 /proc/cpuinfo——更细粒度的CPU档案
lscpu是概览,想看每个逻辑CPU的详细信息,就得翻/proc/cpuinfo。
$ cat /proc/cpuinfo | head -30
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 85
model name : Intel(R) Xeon(R) Gold 6248R CPU @ 3.00GHz
stepping : 7
microcode : 0x500320a
cpu MHz : 3000.000
cache size : 36608 KB
physical id : 0
siblings : 16
core id : 0
cpu cores : 8
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 22
wp : yes
这里我重点看三个字段:
- processor:逻辑CPU编号,从0开始
- physical id:属于哪颗物理CPU
- core id:属于哪个物理核心
为什么要看这三个?
举个例子。假设你看到processor 0和processor 16的physical id都是0,core id都是0。这说明什么?它们其实是同一个物理核心上的两个超线程兄弟。你如果把两个计算密集型的线程绑到这两个核上,它们会抢同一个执行单元,性能反而下降。
我的经验:在交易系统中,收报线程和计算线程一定要绑到不同的物理核心上。我曾经在一个项目里,把两个高频线程绑到了同一个物理核心的两个超线程上,结果丢包率直接翻倍。排查了两天才发现是这个问题。
1.3 cpuinfo_cur_freq——实时频率监控
光看静态信息还不够。CPU频率是会动态变化的,尤其是现在的Intel和AMD处理器,都有睿频和节能机制。
实时频率怎么看?
$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
3000000
单位是kHz。3000000 kHz = 3.0 GHz。
但注意——这个文件不是所有内核版本都支持。如果找不到,可以试试:
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
3000000
这两个文件有什么区别?
| 文件 | 含义 | 可用性 |
|---|---|---|
| cpuinfo_cur_freq | 硬件上报的当前频率 | 部分内核/驱动支持 |
| scaling_cur_freq | 调频策略决定的当前频率 | 几乎都支持 |
避坑指南:我曾经在某个云服务器上发现cpuinfo_cur_freq一直显示为0,以为是硬件坏了。后来才发现是虚拟化环境不支持这个接口。所以建议优先用scaling_cur_freq,兼容性更好。
为什么要监控实时频率?
做量化交易的朋友都知道,延迟就是金钱。如果你的CPU因为温度过高或者节能策略,从3.0GHz降到了2.0GHz,你的交易延迟可能从10微秒变成15微秒。在纳秒级竞争的市场里,这5微秒可能就是胜负手。
我建议在交易系统上线前,跑一个频率监控脚本:
#!/bin/bash
# 监控所有CPU核心的实时频率
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
cpu_num=$(basename $cpu | grep -o '[0-9]\+')
freq=$(cat $cpu/cpufreq/scaling_cur_freq 2>/dev/null)
echo "CPU $cpu_num: $((freq / 1000)) MHz"
done
跑完之后,看看所有核心的频率是否一致。如果某个核心频率明显偏低,那可能就是散热问题或者硬件故障。
1.4 知识体系总览
说了这么多,咱们用一张图把CPU信息查看的知识体系串起来:
这张图把三个工具的关系理清了。lscpu看宏观,/proc/cpuinfo看微观,频率监控看动态。三者结合,你才能对CPU的拓扑和状态了如指掌。
一句话总结:绑核之前,先看拓扑。不看拓扑就绑核,就像闭着眼睛开车——迟早要出事。
好了,CPU信息查看就讲到这里。下一章咱们聊聊怎么把这些信息用到实际的绑核操作中。记住我今天说的——先摸清家底,再动手干活。
公众号:蓝海资料掘金营,微信deep3321