<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Linux on Yu's Space</title><link>https://code-agree.github.io/tags/linux/</link><description>Recent content in Linux on Yu's Space</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Thu, 27 Aug 2026 00:10:00 +0800</lastBuildDate><atom:link href="https://code-agree.github.io/tags/linux/index.xml" rel="self" type="application/rss+xml"/><item><title>低延迟 Socket 优化:从成本模型到平台层</title><link>https://code-agree.github.io/blog/2026-08-27-low_latency_socket/</link><pubDate>Thu, 27 Aug 2026 00:10:00 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-08-27-low_latency_socket/</guid><description>一份自顶向下的分析框架。目标不是罗列参数,而是建立&amp;quot;为什么&amp;quot;的因果链—— 每一项优化都应该能追溯到它消除了哪一类物理成本。
0. 方法论:为什么不能从参数列表开始 #&amp;ldquo;Socket 有哪些优化&amp;quot;是一个被问烂了的问题,而绝大多数答案是失败的,因为它们是平铺的清单: TCP_NODELAY、SO_REUSEPORT、零拷贝、DPDK……
清单式回答有三个致命缺陷:
无法判断适用性。同一个参数在吞吐场景和延迟场景下的取值是相反的,脱离目标谈优化没有意义。 无法排序。不知道哪一项值 10μs、哪一项值 100ns,就会把精力花在错误的地方。 无法发现清单外的问题。真实系统的瓶颈常常不在清单上——它在 BIOS 里、在 NUMA 拓扑里、在 cache 替换策略里。 本文采用的路径是:
解剖数据路径 → 建立成本模型 → 确立度量纪律 → 逐层消除成本 → 验证 (第 1 节) (第 2 节) (第 3 节) (第 4-7 节) (第 8 节) 核心论点:Socket 优化的本质是在从网线到应用逻辑的路径上,系统性地消除排队点、 切换点、拷贝点和失效点。所有具体参数都是这四个原理在不同层次上的投影。
1. 解剖:一个包到底经历了什么 #1.1 接收路径(RX) #① NIC 收包,DMA 写入 RX ring 预挂的 buffer ② NIC 触发 MSI-X 中断(可能被 interrupt coalescing 延迟) ③ 硬中断处理:屏蔽该队列中断,raise NET_RX softirq ④ softirq 上下文 napi_poll:取 descriptor,构造 skb,GRO 聚合 ⑤ netif_receive_skb → ip_rcv → tcp_v4_rcv 查 socket hash → 加 socket 锁 → 序号检查 → 入 receive_queue ⑥ sk_data_ready → wake_up → try_to_wake_up 目标线程若在别的核 → 发 IPI → 对端调度器抢占 ⑦ 用户态 epoll_wait 返回 → recv() → copy_to_user 第一个反直觉的结论:第 ⑤ 步——真正的 TCP 协议处理——在 fast path 上只有几百纳秒。 而整条路径的 wire-to-app 延迟通常是 5–15μs。</description></item><item><title>rdtsc 计时:为什么 TSC 恒速、为什么 rdtscp、为什么标定而非假设</title><link>https://code-agree.github.io/blog/2026-08-26-rdtsc/</link><pubDate>Wed, 26 Aug 2026 08:00:00 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-08-26-rdtsc/</guid><description>HFT 系统里几乎所有 µs 级延迟数字都出自同一个源头:rdtscp 读数 × 一个启动时标定的换算系数。这套做法为什么合理?本文不罗列&amp;quot;最佳实践&amp;quot;,而是把三个设计决策(依赖 TSC 不变性、选 rdtscp 而非 rdtsc、实测标定而非假设频率)各自的备选方案摆出来逐一淘汰——每个选择都有它的道理,换一个前提,结论就会不同。
0. 问题定义:测 µs 级延迟,需要一个什么样的钟? #从需求出发,一个用于延迟测量的时钟必须同时满足四条:
读取开销远小于被测量程——测 µs 级区间,读钟本身必须是 ns 级; 恒速——两次读数之差必须正比于真实流逝时间,比例系数恒定; 单调——不回退; 跨核可比——打点发生在不同线程/进程/核上,读数必须在同一把尺上。 候选其实有两个。clock_gettime(CLOCK_MONOTONIC) 走 vDSO,不进内核,~20ns,四条都满足;TSC(Time Stamp Counter)一条指令直读,~10ns。但这不是二选一——vDSO 的 clock_gettime 底层就是&amp;quot;读 TSC + 用内核维护的系数换算&amp;quot;,它是 TSC 的包装,不是替代品。选择裸读 rdtscp,买到的是三样东西:开销再减一半(打点在最热的路径上,10ns 也值得省);可以只存原始 tick、离线再换算——热路径连乘除都免了;换算系数自己掌控(§3 会讲为什么这很重要)。代价是换算的正确性要自己负责——这正是本文其余部分的主题。而这一切成立的前提是 TSC 满足第 2、4 条,这并非天经地义——第一节先把它论证清楚。
1. 为什么 TSC 恒速(invariant)——一个计数器不能同时忠于&amp;quot;周期&amp;quot;和&amp;quot;时间&amp;quot; #TSC 诞生时(Pentium 时代)真的是周期计数器:每个核心时钟周期 +1。那时 CPU 频率固定,周期数 × 周期长度 = 时间,二者等价,没有矛盾。
矛盾由两个硬件演化引入:
变频(SpeedStep/Turbo):核心频率随负载在 1.2GHz~4GHz 之间滑动 → 同样的周期数对应不同的时间; 休眠(C-states):核心时钟直接停掉 → 周期计数停止,时间却在流逝。 于是出现一个不可回避的分岔:当频率可变时,&amp;ldquo;数周期&amp;quot;和&amp;quot;数时间&amp;quot;成为两个互斥的语义,一个计数器只能忠于其中一个。 Intel 的选择是时间:</description></item><item><title>虚拟内存与 Page Table:从一次访存看懂 MMU、TLB、Page Fault 的完整机制</title><link>https://code-agree.github.io/blog/2026-08-25-page_table/</link><pubDate>Tue, 25 Aug 2026 09:00:00 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-08-25-page_table/</guid><description>进程隔离、共享内存、huge page、lazy allocation、段错误——这些看似独立的现象,底层是同一个机制的不同侧面:page table(页表)。本文从零把它讲透,并在最后把上述现象逐一&amp;quot;接回&amp;quot;这张表。
0. 起点:程序里的地址全是虚拟的 #你代码里的每个指针、每个 &amp;amp;变量,都是 virtual address(虚拟地址)——不是内存条上的真实位置。CPU 拿到它不能直接访问 RAM,必须先翻译成 physical address(物理地址)。
为什么要虚拟化?直接用物理地址的世界没法过:所有程序挤在同一片真实内存里互相可踩(无隔离)、程序必须预知自己被装载到哪(无法重定位)。虚拟化后,每个进程都以为自己独占一条平坦的地址空间,真实内存的分配、位置、给不给,由 OS 在翻译层暗中操作。
1. Page 与 page table:按页翻译的字典 #翻译不能按字节做(字典会比内存还大),所以按 page(页) 做:
虚拟地址空间切成 4KB 一页 → page 物理内存切成 4KB 一块 → page frame(页帧) page table = &amp;ldquo;virtual page number → physical frame number&amp;rdquo; 的对照字典,每个进程一本 字典的每个词条 = PTE(page table entry) virtual address (64bit) = [ virtual page number ][ offset(12bit) ] │查 page table │原样保留 ▼ ▼ physical address = [ physical frame number ][ offset ] 每一次访存(每条 load/store)都要经过这次翻译,执行者是 CPU 里的硬件单元 MMU(Memory Management Unit)——&amp;ldquo;隔离由硬件强制&amp;quot;就是这个字面意思。</description></item><item><title>从 send() 到网线：Linux 网络发包全路径与缓冲区概念辨析</title><link>https://code-agree.github.io/blog/2026-06-26-tcp_send_path/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-06-26-tcp_send_path/</guid><description>本文是《从网线到策略引擎：Linux 网络收包全路径深度解析》的镜像篇。收包讲的是「数据如何从网卡到达用户态」，本文反过来，讲一个本地用户态的数据如何通过 TCP 发送到对端，并顺带把几个最容易混淆的概念——网卡、socket、socket 缓冲区、网卡缓冲区、内核缓冲区——一次性辨析清楚。
〇、先把概念辨析清楚（这是理解全流程的地基） #很多人讲发包讲不清，根子在于把不属于同一层的东西当成一回事。这几个词其实分属三个层次。
1. socket —— 是「对象」，不是「缓冲区」 #socket 是内核里的一个数据结构，代表「一条通信端点」。你 socket() 拿到的 fd，背后就是它。它记着源/目的 IP、端口、协议、连接状态、收发队列指针、TCP 状态机变量等。
socket 是「这条连接的档案 + 控制中心」，本身不存数据，但挂着两个缓冲区。
2. socket 缓冲区 —— per-socket 的软件收发队列 #每个 socket 自带两个队列：
发送缓冲区（send buffer，SO_SNDBUF）：send() 写进来的数据先攒在这。对 TCP，它还兼任重传底本——没收到 ACK 的数据必须留在这里。 接收缓冲区（recv buffer，SO_RCVBUF）：收到的数据攒在这等 recv()。 它在内核内存里，由协议栈管理。
3. 内核缓冲区 —— 一个泛称 #这个词最容易含糊，它不是某个具体东西：
狭义场景下，「内核缓冲区」常就指上面的 socket 缓冲区——相对「用户缓冲区」而言，数据从用户态拷进内核态的那块。 广义上，还包括数据在协议栈里流转时的载体——sk_buff（skb）：内核描述一个网络包的核心结构，封装 TCP/IP/以太网头就是往它上面填。 记法：用户缓冲区 ↔ 内核缓冲区，是「用户态 vs 内核态」这条线；socket 缓冲区是内核缓冲区里最靠近应用的那一段。
4. 网卡（NIC）—— 硬件 #真正把数据变成电信号/光信号送上线的 PCIe 硬件设备。CPU 通过「描述符 + 寄存器（门铃）+ DMA + 中断」这套接口跟它打交道。</description></item><item><title>HFT 系统中的延迟测量与绝对时间戳：一份工程实践指南</title><link>https://code-agree.github.io/blog/2026-04-27-timestamp/</link><pubDate>Mon, 27 Apr 2026 00:42:44 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-04-27-timestamp/</guid><description>面向 Linux/x86_64 平台,覆盖进程内耗时测量、端到端链路延迟、日志时间戳以及监管合规场景。
0. 为什么 HFT 对&amp;quot;时间&amp;quot;如此苛刻 #在高频交易系统里,&amp;ldquo;时间&amp;quot;其实包含三个不同的工程问题,它们的解法几乎没有交集,初学者最容易混为一谈:
相对延迟(Relative Latency):我执行一段代码/一次订单处理花了多少纳秒?内部哪段代码是瓶颈?这关心单机内的时间差,要求极低的测量开销和极高的精度。 本机间隔与超时(Local Intervals):每 5 分钟跑一次校对、心跳 30 秒一次、订单 100 ms 内未回报视为超时——这关心单机内的时间流逝,要求时钟单调、不被 NTP 跳变干扰。 绝对时间戳与跨机器比较(Absolute Timestamp):某事件发生在 UTC 的哪一刻?接收时刻和交易所发出时刻差多少?这关心与外界对齐的墙上时间,要求与交易所、监管的时间基准一致,MiFID II RTS 25 规定业务时钟偏离 UTC 不得超过 100 μs。 第一类追求极致的低开销(单次测量 &amp;lt;10 ns),第二类追求逻辑正确性(不能被时钟跳变坑),第三类追求极致的对齐精度(与 UTC 偏差 &amp;lt;1 μs)。本文按这三条主线展开。
1. Linux 上的时钟源总览 #把所有候选工具按&amp;quot;离硬件远近&amp;quot;排一次,对应它们的精度、开销和 HFT 可用性:
工具 精度 单次开销 HFT 适用 说明 rdtsc / rdtscp CPU 周期(~0.3 ns) 15~40 cycles(~5~15 ns) ✅ 首选 进程内热路径唯一能做到个位数纳秒开销的手段 clock_gettime(CLOCK_MONOTONIC) (vDSO) 纳秒 ~20~30 ns ✅ 常用 底层也是 TSC + 换算,省去自己标定 clock_gettime(CLOCK_MONOTONIC_RAW) 纳秒 ~20~30 ns ⚠️ 特殊 不受 NTP 频率调整,更&amp;quot;原生&amp;rdquo; clock_gettime(CLOCK_REALTIME) 纳秒 ~20~30 ns ❌ 测延迟 / ✅ 打墙钟 会被 NTP 跳变,不能用于计算耗时 clock_gettime(CLOCK_TAI) 纳秒 ~20~30 ns ✅ 日志 不含闰秒,但仍会跟随系统墙钟 step gettimeofday() 微秒 ~20 ns ❌ 精度不够,POSIX 已不推荐 HPET 10~100 ns 几百 ns ~ 1 μs ❌ MMIO 访问,比 TSC 慢数十倍 NIC 硬件时间戳 数十 ns(含 PHY) 内核旁路返回 ✅ 必备 唯一能测 wire-to-wire 的手段 time() / clock() 秒 / 进程 CPU 时间 — ❌ time() 太粗,clock() 不是墙钟 表中的 clock_gettime 开销默认假设 x86_64 新内核走 vDSO。较老内核上 CLOCK_MONOTONIC_RAW/CLOCK_TAI 可能退化为 syscall,开销会高出数倍。</description></item><item><title>kernel socket vs DPDK：一条 WebSocket 帧的两段旅程与纳秒级实测</title><link>https://code-agree.github.io/blog/2026-04-25-kernel_socket_vs_dpdk/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-04-25-kernel_socket_vs_dpdk/</guid><description>— 一条 180 字节的 TLS 帧，从网卡到用户回调，在两条路径上分别要走多久？走哪些步骤？为什么差 3-10 倍？
0. TL;DR #本文做三件事：
走一遍 kernel socket 收包路径——9 步，每步做什么，花多少纳秒 走一遍 DPDK + F-Stack + BIO_s_mem 路径——5 步，每步的用户态替代品 **用真实项目数据（FlashShark-ws，AWS EC2 VM，60 s，n=26 835）**对比两条路径的差距，包括一组真 A/B 对照（M0 kernel 9.6 µs vs M7 DPDK 2.8 µs 的 TLS 解密段） 最硬的两个数：
一条 180 B 的 Binance bookTicker 帧在 DPDK 路径上 e2e p50 = 5.3 µs、min = 1.1 µs 同样的 TLS 解密工作，kernel socket + OpenSSL BIO_s_socket 路径 p50 ≈ 9.</description></item><item><title>低延迟系统的 CPU 核心规划：从 isolcpus 到 Busy Poll 的内核级实战</title><link>https://code-agree.github.io/blog/2026-03-30-cpu_bindcore/</link><pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate><guid>https://code-agree.github.io/blog/2026-03-30-cpu_bindcore/</guid><description>上一篇文章《从网线到策略引擎：Linux 网络收包全路径深度解析》解决的是&amp;quot;数据包怎么走&amp;quot;的问题——从物理层到用户态的七个阶段。本文解决的是&amp;quot;CPU 核心怎么分&amp;quot;的问题——在一个多核系统上，哪些核跑内核家务活、哪些核处理网卡中断、哪些核跑行情线程，以及为什么这样分配。
一、问题的起点：能不能把所有核都 isolate 掉？ #在低延迟系统中，isolcpus 是最常见的核心隔离手段。它的作用是将指定的 CPU 从内核调度器的默认调度域中移除，使得普通进程不会被自动调度到这些核上，从而为延迟敏感的用户线程提供&amp;quot;干净&amp;quot;的执行环境。
一个自然的想法是：既然隔离能减少干扰，那把所有核都隔离了，再手动把用户线程绑上去，岂不是最干净？
这样做不合理，甚至可能导致系统无法正常运行。
1.1 内核的&amp;quot;家务活&amp;quot;必须有人干 #Linux 系统的正常运行依赖大量内核线程和基础设施：
ksoftirqd/N — 每个 CPU 上的软中断处理线程 kworker/N:M — 工作队列线程（延迟工作、异步 I/O 等） rcu_preempt — RCU 回调处理 migration/N — 进程迁移 watchdog/N — CPU 死锁检测 systemd (PID 1) — 用户空间初始化 sshd / journald — 基础系统服务 当你用 isolcpus=0-191 把所有 192 个核都隔离后，这些内核线程和系统服务没有任何核可以正常调度。较新的内核在启动早期会检查是否至少存在一个 housekeeping CPU，如果全部隔离，系统可能直接启动失败或行为异常。
1.2 CPU 0 的特殊地位 #即使不全部隔离，把 CPU 0 隔离也需要格外小心。在 Linux 内核中，CPU 0 承担着特殊职责：
Boot CPU：系统启动阶段的大量初始化逻辑绑定在 CPU 0 上执行，部分内核子系统硬编码依赖它。start_kernel() → rest_init() → kernel_init() 这条初始化链路始终在 CPU 0 上运行。</description></item><item><title>从网线到策略引擎：Linux 网络收包全路径深度解析</title><link>https://code-agree.github.io/blog/2026-03-17-net_proc/</link><pubDate>Tue, 17 Mar 2026 23:10:26 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-03-17-net_proc/</guid><description>本文以一个真实的加密货币交易系统为背景，系统性讲解 Linux 下一个网络数据包从物理网卡到达用户态应用的完整路径，并结合 AWS Graviton (ARM64) + ENA 网卡 + 192 核环境的实际 IRQ 数据进行分析。
一、全景概览 #一个数据包从交易所服务器发出，到你的策略引擎处理完毕，经历了以下七个阶段：
交易所服务器 │ ▼ ┌─────────────────────────────────────────────────────────┐ │ 阶段 1：物理层 &amp;amp; NIC 硬件 │ │ 网线 → PHY → MAC → On-Chip SRAM暂存 → RSS分流 │ │ → DMA 写入主存 Ring Buffer │ ├─────────────────────────────────────────────────────────┤ │ 阶段 2：硬中断 (Hard IRQ) │ │ NIC 触发中断 → CPU 响应 → 最小化处理后调度 softirq │ ├─────────────────────────────────────────────────────────┤ │ 阶段 3：软中断 &amp;amp; NAPI 轮询 │ │ ksoftirqd / NET_RX_SOFTIRQ → NAPI poll 批量收包 │ ├─────────────────────────────────────────────────────────┤ │ 阶段 4：内核协议栈 │ │ IP 层 → TCP/UDP 层 → 查找 socket → 放入 socket buffer │ ├─────────────────────────────────────────────────────────┤ │ 阶段 5：Socket Buffer │ │ sk_receive_queue 排队等待用户态读取 │ ├─────────────────────────────────────────────────────────┤ │ 阶段 6：用户态唤醒 &amp;amp; 数据拷贝 │ │ epoll_wait 返回 → recv/read → 数据从内核拷贝到用户态 │ ├─────────────────────────────────────────────────────────┤ │ 阶段 7：应用层处理 │ │ JSON 解析 → 策略计算 → 下单 / 信号转发 │ └─────────────────────────────────────────────────────────┘ 下面逐层展开。</description></item><item><title>段错误(SEGV)故障定位排查文档</title><link>https://code-agree.github.io/blog/2026-01-15-debug_procedure2/</link><pubDate>Thu, 15 Jan 2026 10:18:16 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-01-15-debug_procedure2/</guid><description>📋 问题概述 #故障现象：panda_strategy-1.0.0 程序在运行过程中发生段错误(Segmentation Fault)，进程崩溃。
崩溃时间：2026-01-15 01:04:11 CST
崩溃进程：PID 2312019
崩溃线程：adapter-poller[2312082]
信号类型：SIGSEGV (Signal 11)
🔍 排查步骤 #1. 确认崩溃信息 #1.1 使用 coredumpctl 获取崩溃基本信息 #coredumpctl info 2312019 输出结果：
PID: 2312019 (panda_strategy-) UID: 1000 (jason) GID: 1000 (jason) Signal: 11 (SEGV) Timestamp: Thu 2026-01-15 01:04:11 CST (7h ago) Command Line: ./panda_strategy-1.0.0 Executable: /home/jason/panda/panda-strategy/Strategy/out/build/wsl-profile/panda_strategy-1.0.0 Storage: none Message: Process 2312019 (panda_strategy-) of user 1000 dumped core. 关键信息：
✅ 确认崩溃时间：2026-01-15 01:04:11 CST ⚠️ Storage: none - 核心转储文件未保存，但可以尝试其他方法分析 1.</description></item><item><title>Linux Coredump 调试完整指南</title><link>https://code-agree.github.io/blog/2026-01-15-debug_procedure/</link><pubDate>Thu, 15 Jan 2026 10:05:34 +0800</pubDate><guid>https://code-agree.github.io/blog/2026-01-15-debug_procedure/</guid><description>目录 # 概述 Coredump 生成机制 环境检查与配置 Coredump 文件定位 使用 GDB 分析 Coredump 实战案例分析 最佳实践与故障排查 概述 #当 Linux 进程因段错误（SIGSEGV）、总线错误（SIGBUS）等信号异常终止时，系统可以生成 coredump 文件，记录进程崩溃时的完整内存状态。通过分析 coredump，我们可以准确定位崩溃原因，包括：
崩溃时的函数调用栈（Stack Trace） 局部变量和全局变量的值 内存布局和寄存器状态 崩溃发生的精确代码位置 本文档提供一套完整的 coredump 调试流程，从环境配置到深度分析，帮助开发者快速定位和解决程序崩溃问题。
Coredump 生成机制 #2.1 系统级配置：core_pattern #Linux 内核通过 /proc/sys/kernel/core_pattern 控制 coredump 的生成方式：
# 查看当前配置 cat /proc/sys/kernel/core_pattern 常见配置模式：
传统模式：直接生成 core 文件
core 在当前工作目录生成名为 core 的文件。
Systemd-coredump 模式（现代 Linux 发行版默认）：
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e 由 systemd-coredump 服务统一管理，提供压缩、存储和查询功能。
自定义路径模式：
/var/crash/core.%e.%p.%t 生成到指定目录，文件名包含可执行文件名、PID 和时间戳。</description></item><item><title>Linux系统负载定位与分析实战指南</title><link>https://code-agree.github.io/blog/2025-12-04-cpu_debug/</link><pubDate>Thu, 04 Dec 2025 23:27:01 +0800</pubDate><guid>https://code-agree.github.io/blog/2025-12-04-cpu_debug/</guid><description>前言 #在高性能计算场景（如HFT交易系统、实时数据处理等）中，系统负载的精确定位至关重要。本文通过一个真实的系统负载分析案例，系统性地介绍如何使用Linux性能分析工具链，从表面现象深入到根本原因。
本文涉及的工具链 # htop/top: 实时系统资源概览 vmstat: 系统级性能统计 pidstat: 进程级性能分析 其他辅助工具: /proc文件系统、perf、strace等 第一阶段：初步观察 - htop #工具介绍 #htop是top的增强版本，提供彩色、交互式的系统监控界面。相比top，它更直观地展示：
每个CPU核心的使用率 进程/线程列表 内存和Swap使用情况 Load Average（负载平均值） 关键指标解读 #CPU使用率分布 #CPU 0-15: |||||||||||||||||| 100.0% 解读要点：
每核心独立显示：现代多核系统必须分核心观察
颜色含义（通常）：
绿色：用户态进程（user space） 红色：内核态（kernel/system） 蓝色：低优先级进程（nice） 黄色：IRQ（硬件中断） 品红：Soft IRQ（软中断） 灰色：IO Wait 青色：Steal（虚拟化环境） 异常模式识别：
全核心100%：CPU密集型负载，可能是正常业务或失控进程 某些核心100%，其他空闲：不均衡的线程分配或CPU亲和性设置 高IO Wait（灰色）：存储瓶颈 高Soft IRQ（品红）：网络包处理压力大 Load Average深度解析 #Load average: 13.08, 13.23, 12.62 常见误区：Load Average ≠ CPU使用率
Load Average的真实含义：
处于以下状态的进程/线程数量的时间加权平均值：
R状态（Running/Runnable）：正在运行或等待CPU D状态（Uninterruptible Sleep）：不可中断睡眠（通常等待I/O） 三个数字的含义：
第一个：1分钟平均 第二个：5分钟平均 第三个：15分钟平均 解读规则：</description></item><item><title>strace 完全使用指南</title><link>https://code-agree.github.io/blog/2025-07-03-strace/</link><pubDate>Thu, 03 Jul 2025 05:00:56 +0800</pubDate><guid>https://code-agree.github.io/blog/2025-07-03-strace/</guid><description>strace 完全使用指南 #目录 # strace 简介 基础语法 核心参数详解 过滤和跟踪选项 输出格式控制 性能分析参数 实用场景示例 输出解读指南 性能调优技巧 最佳实践 1. strace 简介 #1.1 什么是 strace #strace 是 Linux 系统下的系统调用跟踪工具，它可以：
监控进程执行的所有系统调用 显示系统调用的参数和返回值 统计系统调用的执行时间和频率 跟踪信号传递过程 分析程序的系统级行为 1.2 主要用途 #性能分析 → 找出系统调用瓶颈 故障排查 → 定位程序异常原因 安全审计 → 监控程序系统访问 逆向分析 → 理解程序运行机制 系统调优 → 优化系统调用使用 2. 基础语法 #2.1 命令格式 ## 基础语法 strace [选项] [命令] strace [选项] -p &amp;lt;进程ID&amp;gt; # 示例 strace ls /tmp # 跟踪 ls 命令 strace -p 1234 # 跟踪进程ID为1234的进程 strace -e trace=network curl baidu.</description></item><item><title>Perf Report 分析完全指南 - 高频交易系统性能优化</title><link>https://code-agree.github.io/blog/2025-06-18-how_to_use_perf/</link><pubDate>Wed, 18 Jun 2025 03:03:07 +0800</pubDate><guid>https://code-agree.github.io/blog/2025-06-18-how_to_use_perf/</guid><description>目录 # 高频交易系统性能优化思路 Perf 基础知识 perf record 命令参数详解 采样事件类型 Perf 能分析的关键指标 Perf Report 输出解析 列含义详解 分析方法论 高级分析技巧 实际优化流程 关键指标解读 使用Perf分析内存性能指标 高频交易系统案例分析 高频交易系统性能优化思路 #在高频交易系统中，微秒级的延迟差异可能直接影响交易策略的有效性和盈利能力。使用perf进行性能分析是优化高频交易系统的关键步骤。以下是一个系统化的优化思路：
1. 性能基准建立 #关键指标:
端到端延迟: 从行情接收到下单的完整路径时间 吞吐量: 每秒处理的订单/行情数量 尾延迟: 95/99/99.9百分位延迟 CPU利用率: 核心交易路径的CPU使用情况 # 建立基准性能数据 perf stat -e cycles,instructions,cache-references,cache-misses,branches,branch-misses -o perf_base.data -a -g ./strategyTrade 命令参数解释:
cycles: CPU周期数，用于测量程序执行所需的处理器周期总量 instructions: 执行的指令数，结合cycles可计算IPC(每周期指令数)，评估CPU利用效率 cache-references: 缓存访问次数，表示程序对CPU缓存的总访问量 cache-misses: 缓存未命中次数，高缓存未命中率会导致处理器等待内存，增加延迟 branches: 分支指令执行次数，反映程序中条件判断和跳转的频率 branch-misses: 分支预测失败次数，高失败率会导致流水线刷新，降低CPU效率 -o: 指定输出文件名 -a: 收集所有CPU核心的数据，全系统视图 -g: 收集调用图信息，便于分析函数调用关系 输出示例及解读:
Performance counter stats for &amp;#39;./strategyTrade&amp;#39;: 12,345,678,901 cycles # 总CPU周期数 24,680,046,512 instructions # 总指令数，指令/周期比约为2.</description></item><item><title>Fork机制详解：从基础到高级应用</title><link>https://code-agree.github.io/blog/2025-06-24-fork_system_call_analysis/</link><pubDate>Tue, 15 Oct 2024 02:45:13 +0800</pubDate><guid>https://code-agree.github.io/blog/2025-06-24-fork_system_call_analysis/</guid><description>1. 引言 #Fork是Unix/Linux系统中最基本也是最强大的系统调用之一。它允许一个进程创建一个新的进程,这个新进程是原进程的一个几乎完全相同的副本。本次技术分享将深入探讨fork机制,从基本概念到高级应用。
2. Fork的基本原理 #2.1 什么是Fork #Fork是一个系统调用,用于创建一个新的进程。新进程（称为子进程）是调用进程（称为父进程）的一个几乎完全相同的副本。
2.2 Fork的工作原理 #当一个进程调用fork时:
系统会创建一个新的进程。 新进程与父进程共享只读的代码段(text segment),数据段、堆和栈则通过写时复制(COW)获得独立副本。 子进程获得父进程数据段、堆和栈的副本(写时复制),代码段由于是只读的,始终与父进程共享同一物理页面。 父进程和子进程继续执行fork调用之后的代码。 2.3 Fork的返回值 #Fork调用会返回两次:
在父进程中,返回子进程的PID。 在子进程中,返回0。 这允许程序区分父进程和子进程。
pid_t pid = fork(); if (pid &amp;gt; 0) { printf(&amp;#34;父进程\n&amp;#34;); } else if (pid == 0) { printf(&amp;#34;子进程\n&amp;#34;); } else { perror(&amp;#34;fork失败&amp;#34;); exit(1); } 3. Fork的高级特性 #3.1 写时复制 (Copy-on-Write) #为了提高效率,现代操作系统使用&amp;quot;写时复制&amp;quot;技术:
初始时,子进程与父进程共享同一物理内存。 只有当其中一个进程尝试修改内存时,才会创建该部分内存的副本。 这大大减少了fork的开销和内存使用。
3.2 文件描述符的继承 #子进程继承父进程的文件描述符。这意味着:
子进程可以访问父进程打开的文件。 父子进程共享文件偏移量。 int fd = open(&amp;#34;example.txt&amp;#34;, O_RDWR); if (fork() == 0) { // 子进程 write(fd, &amp;#34;Hello from child&amp;#34;, 16); } else { // 父进程 write(fd, &amp;#34;Hello from parent&amp;#34;, 17); } 3.</description></item></channel></rss>