深入 perf 第二版(二):用原始事件编号解锁 CPU 的隐藏指标

系列文章《深入 perf 第二版:理解 CPU 的每一个时钟周期》第 2 篇

perf list 列出的命名事件只覆盖了 PMU 硬件支持事件的一小部分。ARM Cortex-A76 有数百个硬件事件,perf 内置的只有二十几个。本文教你用原始事件编号直接与 PMU 硬件对话,并用 STALL_FRONTEND/STALL_BACKEND 做 Top-Down 微架构分析。
"Not everything that counts can be counted, and not everything that can be counted counts."

(不是所有重要的东西都能被计量,也不是所有能计量的东西都重要。)

------ William Bruce Cameron

上一篇我们掌握了 cycles、instructions、IPC 这三个基础指标(第 1 篇《你真的会用 perf 吗?从 cycles 和 instructions 说起》)。但 perf list 能列出的事件只是冰山一角------本篇教你用原始事件编号,直接读取 PMU 的数百个隐藏指标。

[提示] :本篇假设你已读过第 1 篇的 cycles/instructions/IPC 概念。如果对 perf stat 的基本用法还不熟悉,建议先回看第 1 篇。


3. 原始 PMU 事件编号(Raw Event)

3.1 为什么需要原始事件

团队怀疑某个后端服务存在流水线后端停顿瓶颈------IPC 只有 0.4,但 perf list 里翻来翻去找不到 STALL_BACKEND 这个事件。直到有人翻出 ARM Cortex-A76 的 Technical Reference Manual,发现后端停顿对应事件编号 0x24,用 perf stat -e r0024 手动指定,一条命令就确认了 56% 的 cycles 浪费在后端停顿上。谜底揭开了------但如果不知道原始事件编号这个"后门",这个瓶颈可能永远藏在暗处。

那么,什么是原始事件编号?简单说,它是绕过 perf 内置别名、直接用十六进制数字指定 PMU 硬件事件的方式

perf list 列出的是内核预定义的事件别名,但这只覆盖了 PMU 硬件支持的一小部分事件。例如:

bash 复制代码
perf list | grep -c "Hardware"   # 通常只有 10~20 个预定义硬件事件

而一颗现代 CPU 的 PMU 往往支持 上百个 微架构事件(前端停顿、后端停顿、各级 cache 详细统计、TLB 事件等)。要使用这些事件,就需要通过原始事件编号(Raw Event) 来指定。在第 1 篇中我们用 perf stat -e cycles,instructions 采集命名事件,而原始事件编号让你突破这个"菜单"的限制,直接点"隐藏菜单"。

3.2 ARM64 原始事件语法

ARM64 的 PMU 事件编号存储在 PMEVTYPER(Performance Monitors Event Type Register,事件类型选择寄存器)中,语法为:

text 复制代码
rXXXX

其中 XXXX 是事件编号的十六进制表示。PMEVTYPER 寄存器的 evtCount 字段为 16 位(bits [15:0]),但常用事件集中在低 10 位(0x0000-0x03FF),所以常见事件通常只需 2-3 位十六进制。其中 0x0000-0x003F 为架构级事件,从 0x0040 起为微架构级事件(Implementation-defined)。

这两个范围的区别很实际:架构级事件 (如 0x08 INST_RETIRED、0x11 CPU_CYCLES)是 ARM 架构定义的通用事件,主流 ARMv8 CPU 广泛支持(其中 CPU_CYCLES 等核心事件为强制实现,STALL_FRONTEND 等为推荐实现)------你写的 perf 命令在 Cortex-A76 和 Neoverse N1 上都能跑。微架构级事件 (从 0x0040 起,部分核心还有 0x4000+ 扩展范围)则是各厂商自定义的,只在特定核心上有效。换句话说,架构级事件是"通用菜单",微架构级事件是"特色菜"------换一家餐厅(换一颗 CPU)可能就点不到了。

bash 复制代码
# 例如:STALL_FRONTEND 的事件编号是 0x23
perf stat -e r0023 ./my_program

# STALL_BACKEND 的事件编号是 0x24
perf stat -e r0024 ./my_program

# 同时统计多个原始事件
perf stat -e r0023,r0024,r0011 ./my_program   # r0011 = CPU_CYCLES

等一下------如果 PMU 通用计数器只有 4-6 个(以 Cortex-A76 为例是 6 个),我同时指定 10 个原始事件怎么办?

好问题。这就是 multiplexing(多路复用) 要解决的问题。当事件数超过硬件计数器数量时,内核会在时间片之间轮转分配计数器,最后按比例线性缩放估算总数(估算值 = 采集值 × enabled_time / running_time)。代价是精度下降------perf 输出中会出现类似 (83.33%) 的百分比,表示该事件只有 83% 的时间在实际计数。所以关键事件尽量控制在 4-6 个以内,避免 multiplexing 影响精度。

[提示] :ARM64 PMUv3 有一个专用的周期计数器 PMCCNTR,独立于 6 个通用计数器。这意味着 cycles(CPU_CYCLES)不占用通用计数器名额------当你同时监控 cycles 和其他 6 个事件时,实际上用的是 PMCCNTR + 6 个通用计数器,不会触发 multiplexing。但 instructions(INST_RETIRED)没有专用计数器,会占用一个通用名额。

3.3 x86 原始事件语法

x86 的 PMU 事件由两部分组成:Event 编号 + Umask,最常见的短格式为:

text 复制代码
rUUEE

其中:

  • EE(低字节):Event 编号------选择要监控的事件类别
  • UU(高字节):Umask(子事件选择器)------在该类别内筛选具体子类型

为什么 x86 需要两部分,而 ARM 只用一个编号?因为 x86 PMU 的设计是"一个 Event 编号对应一组相关事件,用 Umask 位选择要计哪几种"。举个例子:Event 0x24 代表 "L2 请求"这一大类,Umask 0x3F 选择其中的 "所有 miss",而 Umask 0x01 只选 "demand 读 miss"。好处是一个 Event 编号能覆盖多个细分场景;代价就是语法比 ARM 复杂一层。

bash 复制代码
# 例如:L2_RQSTS.MISS(L2 cache 请求 miss,以 Skylake 为例)
# Event = 0x24, Umask = 0x3F
# 注意:Umask 值因微架构而异,其他微架构需查阅对应 SDM 或 perfmon event list
perf stat -e r3F24 ./my_program

# MEM_LOAD_RETIRED.L3_MISS
# Event = 0xD1, Umask = 0x20
perf stat -e r20D1 ./my_program

[注意]rUUEE 只是最简单的短格式。现代 Intel CPU(如 Sapphire Rapids)的某些事件还需要 cmaskinvedgeany 等额外字段,完整格式可以扩展到 rNNNNNNNN(最多 8 位十六进制)。遇到复杂事件时,建议使用 cpu/event=0xEE,umask=0xUU,cmask=N/ 完整语法(见 3.4 节),更清晰也更不容易出错。详见 Intel SDM(Software Developer's Manual)Vol. 3 Performance Monitoring 章节。
[提示] 试一试 :在你的 x86 机器上运行 perf list pmu,找到一个感兴趣的事件和它的编号,然后用 rXXXX 格式采集一次数据。例如 perf stat -e r3F24 sleep 1,看看能否成功采集到 L2 cache miss 数据。

3.4 完整语法与 name= 别名技巧

除了简写的 rXXXX,perf 还支持更具可读性的完整语法:

ARM64 完整语法

bash 复制代码
# 格式:armv8_pmuv3/event=0xNN/
perf stat -e armv8_pmuv3/event=0x23/ ./my_program

# 加上 name= 别名,让输出更易读
perf stat -e armv8_pmuv3/event=0x23,name=stall_frontend/ ./my_program
perf stat -e armv8_pmuv3/event=0x24,name=stall_backend/ ./my_program

使用 name= 后,perf 输出中会显示你指定的名称,而不是难以辨认的事件编号:

text 复制代码
# 不带 name=
    850,000,000      armv8_pmuv3/event=0x23/

# 带 name=
    850,000,000      stall_frontend

x86 完整语法

bash 复制代码
# 格式:cpu/event=0xEE,umask=0xUU/
perf stat -e cpu/event=0x24,umask=0x3F,name=l2_miss/ ./my_program

[提示]name= 别名只影响显示,不影响实际采集的事件。善用 name= 能让复杂的 perf stat 输出变得一目了然。

3.5 如何查找事件编号

事件编号可以从以下渠道获取:

方法 1:sysfs 文件系统

bash 复制代码
# 列出所有 PMU 事件
ls /sys/bus/event_source/devices/armv8_pmuv3/events/
# 或者 x86
ls /sys/bus/event_source/devices/cpu/events/

# 查看某个事件的编号
cat /sys/bus/event_source/devices/armv8_pmuv3/events/stall_frontend
# 输出类似:event=0x23

方法 2:ARM 架构参考手册(TRM)

  • 对于 ARM64 通用事件:参考 Arm Architecture Reference Manual(ARMv8-A)的 PMU 章节
  • 对于特定核心的微架构事件:参考对应核心的 Technical Reference Manual(如 Cortex-A76 TRM)

方法 3:内核源码

bash 复制代码
# ARM64 通用事件定义
# 文件路径:arch/arm64/kernel/perf_event.c 或 include/linux/perf/arm_pmuv3.h

# x86 事件映射
# 文件路径:arch/x86/events/intel/core.c

方法 4:perf list 查询

bash 复制代码
# 列出所有事件(推荐,所有版本通用)
perf list

# 按类型筛选
perf list hw                # 只看硬件事件
perf list pmu               # 按关键词 "pmu" 筛选(行为随版本而异)

# 某些版本支持 raw dump 模式
perf list --raw-dump pmu    # 较早版本
perf list --raw-dump        # 较新版本可能不带 pmu 参数
perf list -j                # JSON 格式输出(较新版本,约 6.x+)

[注意]perf list 的子命令和参数在不同版本间有变化。如果某个命令报错,先用 perf list pmu 作为通用替代。

3.6 常见问题与避坑

使用原始事件之前,先了解这几个常见坑:

权限问题

bash 复制代码
# 检查当前权限级别
cat /proc/sys/kernel/perf_event_paranoid
# -1:完全禁用限制(等同 root,仅用于开发/测试环境)
#  0:允许非 root 访问所有 CPU 事件(含内核态)
#  1:非 root 只能采集用户态事件(默认值)
#  2:非 root 只能采集自己进程的用户态事件
#  3(Debian/Ubuntu 特有):非 root 完全禁止

# 临时放开限制(需 root)
echo 0 > /proc/sys/kernel/perf_event_paranoid

[注意] :当 perf_event_paranoid >= 2 时,非 root 用户使用原始事件可能报 Permission denied。生产环境建议通过 CAP_PERFMON capability 授权,而不是全局降低 paranoid 级别。

虚拟化环境

在虚拟机中,PMU 事件可能不完整或不可用------KVM 需要配置 vPMU 透传(-cpu host-cpu xxx,pmu=on),否则只能看到少数模拟的通用事件。容器环境中通常可以正常使用宿主机 PMU(除非被 seccomp 或 cgroup 限制)。

PMU 名称差异

不同内核版本中 PMU 设备名称可能不同。ARM64 上通常是 armv8_pmuv3,但某些旧内核或特定平台可能使用其他名称。用 ls /sys/bus/event_source/devices/ 确认你的系统上的实际名称。

3.7 ARM64 常用 PMU 事件速查表

以下是 ARMv8 PMUv3 架构定义的常用事件(所有 ARMv8 CPU 通用):

事件编号 名称 说明
0x01 L1I_CACHE_REFILL L1 指令 cache 未命中
0x02 L1I_TLB_REFILL L1 指令 TLB 未命中
0x03 L1D_CACHE_REFILL L1 数据 cache 未命中
0x04 L1D_CACHE L1 数据 cache 访问次数
0x05 L1D_TLB_REFILL L1 数据 TLB 未命中
0x08 INST_RETIRED 退休指令数(= instructions
0x09 EXC_TAKEN 异常发生次数
0x0A EXC_RETURN 异常返回次数
0x10 BR_MIS_PRED 分支预测失败次数
0x11 CPU_CYCLES CPU 活跃周期(= cycles
0x12 BR_PRED 可预测分支的推测执行次数(包含预测正确和预测错误的分支)
0x13 MEM_ACCESS 数据内存访问次数
0x14 L1I_CACHE L1 指令 cache 访问次数
0x15 L1D_CACHE_WB L1 数据 cache 写回
0x16 L2D_CACHE L2 数据 cache 访问次数
0x17 L2D_CACHE_REFILL L2 数据 cache 未命中
0x18 L2D_CACHE_WB L2 数据 cache 写回
0x19 BUS_ACCESS 总线访问次数
0x23 STALL_FRONTEND 前端停顿周期
0x24 STALL_BACKEND 后端停顿周期
0x25 L1D_TLB L1 数据 TLB 访问次数
0x26 L1I_TLB L1 指令 TLB 访问次数
0x2D L2D_TLB_REFILL L2 数据 TLB 未命中
0x2F L2D_TLB L2 数据 TLB 访问次数
0x31 REMOTE_ACCESS 远端(跨 NUMA)内存访问

[提示] :以上是架构级事件(Architecture-defined),主流 ARMv8 实现普遍支持(其中 CPU_CYCLESINST_RETIRED 等核心事件为强制实现,其余为推荐实现)。具体 CPU 核心(如 Cortex-A76、Neoverse N1)还会有额外的微架构级事件(Implementation-defined),编号通常从 0x40 起,需查阅对应 TRM。

注意 BR_PRED0x12)的含义是"可预测分支推测执行次数"(不区分预测对错),BR_MIS_PRED0x10)只计退休阶段确认的预测失败。两者在流水线不同阶段计数,简单相减并不精确------如需评估分支预测质量,直接看 BR_MIS_PRED / BR_PRED 的比例即可(该比例同样是近似值,但作为趋势指标足够判断分支预测是否存在问题)。

3.8 Uncore PMU 事件简介

前面介绍的所有事件都发生在 CPU 核心"内部"。但有一类性能问题------比如多核竞争 LLC、内存带宽打满------根因并不在核心里,而在核心之间的"公共设施"上。这就需要 Uncore 事件。

Uncore (也叫 Systemoff-core)是指 CPU 核心之外、但仍在芯片上的组件,包括:

  • LLC(Last Level Cache):最后一级缓存(通常 L3)
  • IMC(Integrated Memory Controller):内存控制器
  • 互联总线:核心之间的通信网络(如 Intel 的 Ring Bus / Mesh)
  • PCIe 控制器IO 单元

Uncore 事件用于分析这些共享资源的行为:

bash 复制代码
# 查看系统支持的 Uncore PMU
ls /sys/bus/event_source/devices/ | grep uncore

# x86 示例:统计 LLC miss(PMU 名称因平台而异:
#   Haswell/Broadwell: uncore_cbox_N, Skylake-SP+: uncore_cha_N)
perf stat -e uncore_cbox_0/event=0x34,umask=0x08,name=llc_miss/ -a sleep 5

# ARM64 示例(如果平台支持)
perf stat -e arm_cmn_0/event=0x01,name=cmn_rxflit/ -a sleep 5

[注意]:Uncore 事件有三个重要限制:

  • 必须使用 -a(全系统模式) ,Uncore PMU 不绑定特定进程,缺少 -a 会报错
  • 容器/虚拟机内通常不可用,Uncore PMU 属于物理硬件资源,虚拟化层一般不暴露
  • 多 socket 系统中各 socket 的 Uncore PMU 相互独立 ,需要分别指定(如 uncore_cbox_0 对应第一个 LLC slice)
3.9 实战:用 STALL_FRONTEND + STALL_BACKEND 做 Top-Down 分析

Top-Down 分析方法将 CPU 流水线的效率问题分为几大类。这里使用的是 ARM 简化版 Top-Down 方法 ------用 STALL_FRONTENDSTALL_BACKEND 两个停顿周期计数器来判断瓶颈方向:

text 复制代码
              总 cycles
              /        \
         有效工作     流水线停顿
                     /         \
              前端停顿         后端停顿
             (取指/解码)    (执行/访存)
              STALL_         STALL_
              FRONTEND       BACKEND

[注意] ARM Top-Down vs Intel TMA :Intel 的 TMA(Top-down Microarchitecture Analysis)将每个 pipeline slot 分为四类------Frontend Bound、Backend Bound、Bad Speculation、Retiring,四者加起来恰好 100%。ARM 的方法更简单:STALL_FRONTENDSTALL_BACKEND 只计停顿周期数,二者可能重叠(同一周期前端和后端同时停顿),所以 STALL_FRONTEND + STALL_BACKEND 可能大于 cycles。ARM 的方法用于快速判断瓶颈方向足够好,但不要把它当作精确的百分比分解。详见 ARM Telemetry Solution Guide。

前端停顿意味着什么? 流水线前端负责取指令和解码------如果前端停顿占比高,说明 CPU "吃不饱",可能的原因包括:I-cache miss(代码太大或跳转太多)、ITLB miss(代码分布在太多页上)、指令解码瓶颈(复杂指令序列)。

后端停顿意味着什么? 流水线后端负责执行和访存------如果后端停顿占比高,说明 CPU "消化不了",可能的原因包括:D-cache miss(数据访问模式差)、内存延迟高(穿透到 DDR)、执行单元争用(某类指令太密集)。

步骤 1:采集数据

bash 复制代码
perf stat -e cycles,instructions,\
armv8_pmuv3/event=0x23,name=stall_frontend/,\
armv8_pmuv3/event=0x24,name=stall_backend/ \
./my_program

步骤 2:假设得到以下输出

text 复制代码
 Performance counter stats for './my_program':

     5,000,000,000      cycles
     2,000,000,000      instructions              #    0.40  insn per cycle
     1,500,000,000      stall_frontend
     2,800,000,000      stall_backend

IPC 只有 0.40------第 1 篇我们说过 IPC < 1 需要关注,这里显然有严重的流水线效率问题。接下来用停顿指标定位方向。

步骤 3:展开计算各比例

text 复制代码
前端停顿占比 = stall_frontend ÷ cycles
             = 1,500,000,000 ÷ 5,000,000,000
             = 0.30 = 30%

后端停顿占比 = stall_backend ÷ cycles
             = 2,800,000,000 ÷ 5,000,000,000
             = 0.56 = 56%

有效工作占比 ≈ 1 - 前端停顿占比 - 后端停顿占比
             = 1 - 0.30 - 0.56
             = 0.14 = 14%  (近似值,因停顿可能重叠)

为什么停顿会重叠?因为流水线是多级并行的------前端取指令的同时,后端在执行之前取到的指令。在同一个时钟周期里,前端可能因 I-cache miss 停住,后端也可能因 D-cache miss 停住,两个计数器同时 +1。所以 STALL_FRONTEND + STALL_BACKEND 超过 cycles 是完全正常的。上面的例子中,30% + 56% = 86%,没有超过 100%,说明重叠不多;但如果你看到两者之和达到 120%,说明存在大量前后端同时停顿的周期,需要进一步细化分析定位根因。

步骤 4:解读

分类 占比 解读 下一步细化事件
前端停顿 30% I-cache miss、ITLB miss、指令解码瓶颈 L1I_CACHE_REFILL(r0001)、L1I_TLB_REFILL(r0002)
后端停顿 56% D-cache miss、内存延迟、执行单元争用 L1D_CACHE_REFILL(r0003)、L2D_CACHE_REFILL(r0017)
有效工作 ~14% CPU 流水线效率极低 ---

结论 :后端停顿是主要瓶颈(56%),应重点分析内存访问模式。这一结论也呼应了开头那个故事------当你发现 IPC 异常低,STALL_FRONTEND/STALL_BACKEND 就是你的第一把手术刀。后续的 cache miss 细化分析(L1D/L2/L3),将在第 4 篇《从 L1 到 DRAM》中系统展开。

步骤 5:进一步细化后端停顿

bash 复制代码
perf stat -e cycles,\
armv8_pmuv3/event=0x24,name=stall_backend/,\
armv8_pmuv3/event=0x03,name=l1d_refill/,\
armv8_pmuv3/event=0x17,name=l2d_refill/,\
armv8_pmuv3/event=0x10,name=br_mis_pred/ \
./my_program

[提示] 试一试 :用本项目 tests/ 下的 test_cache_miss 程序体验后端停顿。编译后运行 perf stat -e cycles,instructions,r0023,r0024 ./test_cache_miss random,对比 sequentialrandom 模式下前后端停顿占比的变化------你会看到 random 模式下后端停顿占比显著上升。

3.10 诊断工作流:从 IPC 异常到定位根因

当你用 perf stat 发现 IPC 异常低时,按以下路径逐步缩小范围:

text 复制代码
发现 IPC < 1
    │
    ▼
采集 STALL_FRONTEND (r0023) + STALL_BACKEND (r0024)
    │
    ├── 前端停顿占比高 (>30%)
    │   │
    │   ▼
    │   采集 L1I_CACHE_REFILL (r0001) + L1I_TLB_REFILL (r0002)
    │   │
    │   ├── I-cache miss 高 → 代码布局优化(-ffunction-sections, PGO)
    │   └── ITLB miss 高 → 减少代码页数(合并热点函数、huge page for text(配置复杂,优先考虑 `-ffunction-sections` + link-time layout))
    │
    ├── 后端停顿占比高 (>40%)
    │   │
    │   ▼
    │   采集 L1D_CACHE_REFILL (r0003) + L2D_CACHE_REFILL (r0017) + MEM_ACCESS (r0013)
    │   │
    │   ├── L1D miss 高但 L2 命中 → 优化数据局部性(struct layout、prefetch)
    │   ├── L2 miss 高 → 内存访问模式问题,可能穿透到 DDR
    │   │   → 进一步用第 4 篇《从 L1 到 DRAM》的 cache/TLB/NUMA 事件细化
    │   └── 执行单元争用 → 检查是否有大量除法/浮点/特殊指令
    │
    ├── 两者都高 (前端>30% 且 后端>40%)
    │   └── 内存子系统全面过载,前后端同时受阻 → 优先解决后端(收益更大)
    │
    └── 两者都不高
        └── 可能是指令依赖链、长延迟指令、或 SMT 资源竞争 → 第 3 篇微架构分析

这条链路的核心思想是:先定方向(前端 vs 后端),再钻细节(哪一级 cache、哪类 miss)。避免一上来就采集 20 个事件------既触发 multiplexing 又让自己淹没在数据里。

3.11 速查表

原始事件语法速查

平台 短格式 完整格式 说明
ARM64 rXXXX armv8_pmuv3/event=0xNN/ 事件编号最多 16-bit
x86 rUUEE cpu/event=0xEE,umask=0xUU/ 复杂事件用完整格式
别名 --- name=xxx 只影响显示

Top-Down 快速判断

指标 计算公式 判断标准
前端停顿占比 STALL_FRONTEND / cycles > 30% 需关注前端
后端停顿占比 STALL_BACKEND / cycles > 40% 需关注后端
IPC instructions / cycles < 1 效率低,> 2 优秀
3.12 FAQ

Q1:multiplexing 会影响原始事件的准确性吗?

会。当同时监控的事件数超过硬件 PMU 计数器数量(通常 4-6 个通用计数器)时,内核会在时间片间轮转。perf 输出中出现 (83.33%) 这样的百分比就是 multiplexing 的标志------意味着该事件只有 83% 的时间在实际计数,最终值是估算的。关键指标建议分多次采集,每次不超过 4-6 个事件。

Q2:原始事件能用于 perf record 采样吗?

可以。语法完全一致:perf record -e r0024 ./my_program。采样模式下,每当该事件计数溢出时触发中断采样,可以用 perf report 看到哪些函数触发了最多的后端停顿。

Q3:如何确认某个事件编号在我的 CPU 上可用?

三步验证:(1) 查看 /sys/bus/event_source/devices/armv8_pmuv3/events/ 下是否有对应事件;(2) 用 perf stat -e rXXXX sleep 1 试跑,如果报 not supported 说明当前 CPU 不支持该编号;(3) 对照 CPU 的 TRM 确认事件定义和编号。

Q4:ARM64 和 x86 的事件编号能通用吗?

不能。每个架构、甚至同架构不同微架构的事件编号都不同。ARM 的 0x23(STALL_FRONTEND)在 x86 上毫无意义。跨平台分析时需要分别查阅对应平台的手册。

Q5:为什么 sysfs 里能看到事件名,但 perf list 里没有?

perf list 只显示内核 perf 子系统明确注册的事件别名。sysfs 中的事件来自 PMU 驱动,有时 PMU 驱动暴露了事件但 perf 用户态工具没有对应的别名映射。这正是原始事件编号存在的价值------它不依赖别名,直接用编号访问 PMU 硬件。


下一篇预告:同一段代码,给数组排个序就快了 3 倍------不是编译器优化,不是算法改进。CPU 到底在背后干了什么?第 3 篇《为什么排序后代码快 3 倍?分支预测和流水线的秘密》揭晓答案。

相关推荐
代码中介商2 小时前
Linux 基础命令完全指南:从文件操作到进程管理
linux·运维·服务器
思麟呀2 小时前
应用层协议HTTP
linux·服务器·网络·c++·网络协议·http
一个人旅程~2 小时前
linuxmint如何使用iphone手机上网以及如何管理iphone手机的照片和文件?需要下载哪些基础包和依赖?
linux·windows·经验分享·电脑
异步的告白2 小时前
链接脚本SECTIONS逐行深度解析
linux·开发语言
lwf0061642 小时前
JPA 批量操作性能优化配置
性能优化
heimeiyingwang3 小时前
【无标题】
网络·缓存·docker·性能优化·架构
南境十里·墨染春水3 小时前
linux学习进展 信号
linux·服务器·学习
SiYuanFeng3 小时前
一展使用gpt-5-mini和gemini-3.1-flash-image-preview-0.5k的运行demo代码
linux·python·gpt
YuanDaima20483 小时前
堆(优先队列)基础原理与题目说明
linux·运维·服务器·人工智能·python··代码