Skip to content

I/O系统架构深度解析

课程概述

本教程全面讲解计算机I/O系统的工作原理,从总线架构演进到DMA机制,从中断处理到I/O虚拟化,帮助你深入理解I/O子系统的性能优化策略。

学习目标

  • 理解总线架构的演进历程
  • 掌握PCIe的分层协议和通道机制
  • 深入了解DMA数据传输原理
  • 学会中断处理机制与优化
  • 掌握I/O虚拟化技术(SR-IOV)

1. 总线架构演进

1.1 总线技术发展史

┌─────────────────────────────────────────────────────────────┐
│              总线架构演进时间线                               │
└─────────────────────────────────────────────────────────────┘

1981      1992      2001      2003      2010      2017      2022
 │         │         │         │         │         │         │
 ▼         ▼         ▼         ▼         ▼         ▼         ▼
ISA      PCI      PCI-X    PCIe 1.0   PCIe 3.0  PCIe 4.0  PCIe 5.0
8MB/s    133MB/s  1GB/s    250MB/s    984MB/s   1.97GB/s  3.94GB/s
并行      并行      并行     串行(x1)   串行(x1)  串行(x1)  串行(x1)

带宽对比(x16通道):
PCI         2.1 GB/s   ████
PCI-X       8.5 GB/s   ████████████████
PCIe 1.0    4.0 GB/s   ███████
PCIe 2.0    8.0 GB/s   ██████████████
PCIe 3.0   15.8 GB/s   ███████████████████████████
PCIe 4.0   31.5 GB/s   ██████████████████████████████████████████████████████
PCIe 5.0   63.0 GB/s   ████████████████████████████████████████████████████████████████████████████████████████████████████

架构对比:

传统PCI(并行总线):
┌──────────────────────────────────────────┐
│  CPU                                     │
│   │                                      │
│   ▼                                      │
│  北桥(MCH)                                │
│   │                                      │
│   ├────────────────────────┐             │
│   │    PCI总线(共享)      │  32/64位    │
│   │   ═══════════════      │  33/66MHz   │
│   │    │    │    │         │             │
│   │   设备1 设备2 设备3     │  所有设备    │
│   │                        │  竞争带宽    │
│   │   南桥(ICH)            │             │
│   └────────────────────────┘             │
└──────────────────────────────────────────┘

现代PCIe(点对点串行):
┌──────────────────────────────────────────┐
│  CPU                                     │
│   │                                      │
│   ├─────┬─────┬─────┬─────┐             │
│   │     │     │     │     │             │
│  x16   x8    x4    x4    x1             │
│   │     │     │     │     │             │
│   │     │     │     │     │             │
│  GPU   SSD  网卡  声卡  USB              │
│                                          │
│  每个设备独享通道(无竞争)                │
└──────────────────────────────────────────┘

1.2 PCIe拓扑结构

┌─────────────────────────────────────────────────────────────┐
│              PCIe拓扑架构(PCIe Topology)                    │
└─────────────────────────────────────────────────────────────┘

完整系统拓扑:
                    ┌─────────────┐
                    │     CPU     │
                    │  ┌───────┐  │
                    │  │ PCIe  │  │  Root Complex
                    │  │ Root  │  │  (根复合体)
                    └──┴───┬───┴──┘

        ┌──────────────────┼──────────────────┐
        │                  │                  │
   ┌────▼────┐        ┌────▼────┐       ┌────▼────┐
   │PCIe x16 │        │PCIe x8  │       │PCIe x4  │
   └────┬────┘        └────┬────┘       └────┬────┘
        │                  │                  │
   ┌────▼────┐        ┌────▼────┐       ┌────▼────────┐
   │  GPU    │        │ Switch  │       │   NVMe SSD  │
   │         │        └────┬────┘       └─────────────┘
   │         │             │
   └─────────┘       ┌─────┴─────┐
                     │           │
                ┌────▼────┐ ┌────▼────┐
                │  网卡   │ │  RAID   │
                │  x4     │ │  卡 x4  │
                └─────────┘ └─────────┘

层次结构术语:
┌─────────────────────────────────────────┐
│  Root Complex (RC)                      │  CPU集成
│    │                                    │
│    ├─ Endpoint (设备)                   │  单功能设备
│    │                                    │
│    ├─ Switch (交换机)                   │  扩展端口
│    │   └─ Virtual Bridge (虚拟桥)       │
│    │                                    │
│    └─ Legacy Endpoint                  │  兼容设备
└─────────────────────────────────────────┘

地址空间:
┌──────────────────────────────────────────┐
│  Configuration Space (配置空间)          │
│  - 256B (PCIe 1.x)                      │
│  - 4KB (PCIe 2.0+扩展配置空间)           │
│  - 存储设备ID、BAR等                     │
│                                          │
│  Memory Space (内存空间)                 │
│  - MMIO映射                              │
│  - 设备寄存器访问                         │
│                                          │
│  I/O Space (I/O空间)                     │
│  - 传统I/O端口(逐渐淘汰)                │
└──────────────────────────────────────────┘

2. PCIe协议详解

2.1 PCIe分层架构

┌─────────────────────────────────────────────────────────────┐
│              PCIe协议栈(PCIe Protocol Stack)                │
└─────────────────────────────────────────────────────────────┘

OSI风格分层:
┌──────────────────────────────────────────────────────────┐
│  Transaction Layer (事务层)                               │
│  ┌────────────────────────────────────────────────────┐  │
│  │  - 生成/接收TLP (Transaction Layer Packet)         │  │
│  │  - 管理信用流控(Flow Control)                       │  │
│  │  - QoS虚拟通道(Virtual Channels)                   │  │
│  │  - 排序规则(Ordering Rules)                        │  │
│  └────────────────────────────────────────────────────┘  │
│                          │                                │
│                          ▼                                │
│  ┌────────────────────────────────────────────────────┐  │
│  │  Data Link Layer (数据链路层)                       │  │
│  │  - 添加/验证序列号和CRC                             │  │
│  │  - ACK/NAK协议                                     │  │
│  │  - 重传机制                                         │  │
│  │  - 封装为DLLP (Data Link Layer Packet)            │  │
│  └────────────────────────────────────────────────────┘  │
│                          │                                │
│                          ▼                                │
│  ┌────────────────────────────────────────────────────┐  │
│  │  Physical Layer (物理层)                            │  │
│  │  - 8b/10b编码(PCIe 1.x/2.x)                        │  │
│  │  - 128b/130b编码(PCIe 3.0+)                        │  │
│  │  - 差分信号传输                                     │  │
│  │  - 链路训练和状态机                                 │  │
│  └────────────────────────────────────────────────────┘  │
│                          │                                │
│                          ▼                                │
│                   物理介质(铜线/光纤)                      │
└──────────────────────────────────────────────────────────┘

TLP包结构(Memory Read Request示例):
┌─────────────────────────────────────────────────────┐
│  TLP Header (12-16 bytes)                           │
│  ┌──────┬──────┬───────┬─────────┬─────────────┐   │
│  │ Fmt  │ Type │ Length│Requester│   Address   │   │
│  │ (2b) │ (5b) │(10b)  │ ID (16b)│   (32/64b)  │   │
│  └──────┴──────┴───────┴─────────┴─────────────┘   │
│                                                     │
│  Data Payload (0-4096 bytes)                        │
│  ┌─────────────────────────────────────────────┐   │
│  │  实际数据                                    │   │
│  └─────────────────────────────────────────────┘   │
│                                                     │
│  ECRC (可选,4 bytes)                               │
│  └─────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

TLP类型:
┌────────────────────┬─────────────────────────┐
│  内存请求           │  Memory Read/Write      │
│  I/O请求           │  I/O Read/Write         │
│  配置请求           │  Configuration Read/Write│
│  消息请求           │  Message (中断等)        │
│  完成               │  Completion (响应)       │
└────────────────────┴─────────────────────────┘

2.2 PCIe通道与带宽

┌─────────────────────────────────────────────────────────────┐
│              PCIe通道配置(Lane Configuration)               │
└─────────────────────────────────────────────────────────────┘

物理通道(Lane):
每个Lane = 1对差分信号(TX + RX)

Lane配置:
┌─────────────────────────────────────┐
│  x1:  ─→  (1个Lane)                │
│       ←─                            │
│                                     │
│  x4:  ═══→  (4个Lane并行)          │
│       ←═══                          │
│                                     │
│  x8:  ═══════→  (8个Lane)          │
│       ←═══════                      │
│                                     │
│  x16: ═══════════════→  (16个Lane) │
│       ←═══════════════              │
└─────────────────────────────────────┘

带宽计算:
┌──────────────────────────────────────────────────────┐
│  PCIe世代  编码方式     单Lane速率    x16带宽         │
├──────────────────────────────────────────────────────┤
│  1.0      8b/10b(80%)   250MB/s     4.0 GB/s        │
│  2.0      8b/10b(80%)   500MB/s     8.0 GB/s        │
│  3.0      128b/130b     984MB/s     15.8 GB/s       │
│           (98.5%)                                    │
│  4.0      128b/130b     1.97GB/s    31.5 GB/s       │
│  5.0      128b/130b     3.94GB/s    63.0 GB/s       │
│  6.0      FLIT+PAM4     7.88GB/s    126.0 GB/s      │
└──────────────────────────────────────────────────────┘

编码效率示例:
┌────────────────────────────────────┐
│  8b/10b编码(PCIe 1.x/2.x):       │
│  每8位数据编码为10位传输            │
│  效率:8/10 = 80%                  │
│  原因:用于时钟恢复和DC平衡         │
│                                    │
│  128b/130b编码(PCIe 3.0+):       │
│  每128位数据添加2位同步头           │
│  效率:128/130 = 98.5%             │
│  改进:更高效率,更复杂             │
└────────────────────────────────────┘

实际可用带宽:
┌──────────────────────────────────────┐
│  理论带宽需要减去协议开销:           │
│  - TLP头部(12-20字节)              │
│  - 数据链路层开销(序列号、CRC)      │
│  - ACK/NAK开销                       │
│                                      │
│  有效载荷比例:~85-90%                │
│                                      │
│  示例(PCIe 3.0 x4 NVMe SSD):      │
│    理论带宽:3.94 GB/s               │
│    实际带宽:~3.5 GB/s               │
└──────────────────────────────────────┘

热插拔与链路训练:
┌────────────────────────────────────┐
│  1. 检测阶段(Detect)                │
│     - 检测设备插入                  │
│                                    │
│  2. 轮询阶段(Polling)               │
│     - 协商速率和Lane数量             │
│                                    │
│  3. 配置阶段(Configuration)         │
│     - 交换Link能力                  │
│     - 配置Lane映射                  │
│                                    │
│  4. L0工作状态                      │
│     - 正常数据传输                  │
│                                    │
│  5. 省电状态                        │
│     - L0s: 微秒级恢复                │
│     - L1:  毫秒级恢复                │
│     - L2:  需要重新训练              │
└────────────────────────────────────┘

3. DMA直接内存访问

3.1 DMA工作原理

┌─────────────────────────────────────────────────────────────┐
│              DMA工作流程(DMA Operation)                     │
└─────────────────────────────────────────────────────────────┘

传统PIO(Programmed I/O)模式:
┌────────────────────────────────────────┐
│  1. CPU发起读取请求                     │
│     │                                  │
│     ▼                                  │
│  2. 设备准备数据                        │
│     │                                  │
│     ▼                                  │
│  3. CPU循环检查状态(轮询)               │
│     │  while(!ready) {}                │
│     ▼                                  │
│  4. CPU读取数据到寄存器                 │
│     │                                  │
│     ▼                                  │
│  5. CPU写入内存                         │
│     │                                  │
│     └─→ 重复直到所有数据传输完成         │
│                                        │
│  缺点:CPU全程参与,浪费CPU资源          │
└────────────────────────────────────────┘

DMA模式(CPU解放):
┌────────────────────────────────────────────────────┐
│  CPU                  DMA控制器           设备      │
│   │                      │                 │       │
│   ├─1. 配置DMA──────────→│                 │       │
│   │  (源地址、目标地址、  │                 │       │
│   │   传输大小)           │                 │       │
│   │                      │                 │       │
│   │                      ├─2. 请求数据─────→│       │
│   │                      │                 │       │
│   │                      │←─3. 数据────────┤       │
│   │                      │                 │       │
│   │                      ├─4. 写入内存─────→内存   │
│   │                      │    (总线仲裁)    │       │
│   │                      │                 │       │
│   │                      │  ...重复...     │       │
│   │                      │                 │       │
│   │←─5. 中断通知完成─────┤                 │       │
│   │                      │                 │       │
│   └─6. 处理完成的数据    │                 │       │
│                                                    │
│  优点:CPU只需配置和处理结果,传输期间可做其他任务  │
└────────────────────────────────────────────────────┘

DMA传输类型:
┌──────────────────────────────────────────┐
│  1. 单次DMA (Single Transfer)            │
│     每个DMA请求传输1字节/字               │
│                                          │
│  2. 块DMA (Block Transfer)               │
│     传输整个数据块后释放总线              │
│                                          │
│  3. 周期窃取DMA (Cycle Stealing)         │
│     在CPU不使用总线时窃取周期             │
│                                          │
│  4. 突发DMA (Burst Mode)                 │
│     占用总线传输整个数据块(最快)         │
└──────────────────────────────────────────┘

Scatter-Gather DMA:
┌──────────────────────────────────────────┐
│  问题:数据分散在内存多个不连续位置        │
│                                          │
│  内存布局:                               │
│  ┌────┐                                  │
│  │Buf1│  地址0x1000, 长度4KB             │
│  └────┘                                  │
│  ...   (中间有其他数据)                   │
│  ┌────┐                                  │
│  │Buf2│  地址0x5000, 长度8KB             │
│  └────┘                                  │
│  ...                                     │
│  ┌────┐                                  │
│  │Buf3│  地址0xA000, 长度2KB             │
│  └────┘                                  │
│                                          │
│  Scatter-Gather列表:                    │
│  ┌───────────┬──────┬────────┐          │
│  │ 地址      │ 长度 │ 标志    │          │
│  ├───────────┼──────┼────────┤          │
│  │ 0x1000    │ 4KB  │ More   │          │
│  │ 0x5000    │ 8KB  │ More   │          │
│  │ 0xA000    │ 2KB  │ Last   │          │
│  └───────────┴──────┴────────┘          │
│                                          │
│  DMA引擎自动处理多个分散的缓冲区          │
└──────────────────────────────────────────┘

3.2 IOMMU与DMA重映射

┌─────────────────────────────────────────────────────────────┐
│              IOMMU架构(I/O Memory Management Unit)          │
└─────────────────────────────────────────────────────────────┘

无IOMMU的问题:
┌────────────────────────────────────────┐
│  设备使用物理地址进行DMA                │
│                                        │
│  问题:                                 │
│  1. 安全风险:设备可访问所有物理内存     │
│  2. 地址限制:32位设备无法访问4GB以上   │
│  3. 虚拟化困难:无法隔离VM的设备        │
└────────────────────────────────────────┘

IOMMU解决方案(Intel VT-d / AMD-Vi):
┌────────────────────────────────────────────────────┐
│  设备视角                                           │
│  ┌────────┐                                        │
│  │ NIC    │  发起DMA到地址0x1000                   │
│  └────┬───┘                                        │
│       │                                            │
│       ▼                                            │
│  ┌──────────────┐                                  │
│  │   IOMMU      │  地址转换                         │
│  │              │  0x1000 → 0x8A3F1000 (物理地址)  │
│  └──────┬───────┘                                  │
│         │                                          │
│         ▼                                          │
│  ┌─────────────────┐                               │
│  │  物理内存        │                               │
│  │  0x8A3F1000处   │  实际写入位置                  │
│  └─────────────────┘                               │
│                                                    │
│  优势:                                             │
│  - 设备隔离(每个设备独立地址空间)                  │
│  - 内存保护(设备只能访问授权区域)                  │
│  - 支持虚拟化(SR-IOV直通)                         │
└────────────────────────────────────────────────────┘

DMA地址映射示例:
┌────────────────────────────────────────┐
│  驱动程序申请DMA缓冲区:               │
│                                        │
│  dma_addr_t dma_handle;                │
│  void *cpu_addr;                       │
│                                        │
│  cpu_addr = dma_alloc_coherent(        │
│      dev,                              │
│      size,                             │
│      &dma_handle,   ← 设备使用这个地址  │
│      GFP_KERNEL                        │
│  );                                    │
│                                        │
│  CPU使用cpu_addr访问                   │
│  设备使用dma_handle访问                │
│  IOMMU负责地址转换                     │
└────────────────────────────────────────┘

IOMMU页表结构(类似CPU页表):
┌──────────────────────────────────┐
│  设备虚拟地址 (IOVA)              │
│       │                          │
│       ▼                          │
│  ┌─────────────┐                 │
│  │ IOMMU页表   │  多级页表        │
│  │ 转换        │                 │
│  └──────┬──────┘                 │
│         │                        │
│         ▼                        │
│  物理地址                         │
└──────────────────────────────────┘

4. 中断处理机制

4.1 中断类型与演进

┌─────────────────────────────────────────────────────────────┐
│              中断机制演进(Interrupt Evolution)              │
└─────────────────────────────────────────────────────────────┘

传统中断(Legacy INTx):
┌────────────────────────────────────┐
│  物理中断引脚:INTA#, INTB#, ...   │
│                                    │
│  ┌────────┐                        │
│  │ 设备1  ├───INTA#──┐             │
│  └────────┘          │             │
│  ┌────────┐          │             │
│  │ 设备2  ├───INTB#──┤             │
│  └────────┘          │             │
│                      ▼             │
│               ┌─────────────┐      │
│               │ 中断控制器  │      │
│               │   (PIC)     │      │
│               └──────┬──────┘      │
│                      │             │
│                      ▼             │
│                    CPU             │
│                                    │
│  缺点:                             │
│  - 中断线数量有限(共享中断)        │
│  - 中断风暴问题                     │
│  - 不支持多核亲和性                 │
└────────────────────────────────────┘

MSI (Message Signaled Interrupts):
┌────────────────────────────────────┐
│  通过写内存触发中断(无物理引脚)   │
│                                    │
│  ┌────────┐                        │
│  │ 设备   │                        │
│  │        │                        │
│  │  中断  │                        │
│  │  发生  │                        │
│  └────┬───┘                        │
│       │                            │
│       ├─写入特定内存地址────┐       │
│       │  (0xFEE00000系列)  │       │
│       │  附带中断向量号     │       │
│       │                    │       │
│       ▼                    ▼       │
│   PCIe总线            内存控制器    │
│       │                    │       │
│       └─────────┬──────────┘       │
│                 │                  │
│                 ▼                  │
│             LAPIC (CPU)            │
│                                    │
│  优势:                             │
│  - 每设备独立中断向量                │
│  - 无需物理引脚                     │
│  - 支持多达32个中断                 │
└────────────────────────────────────┘

MSI-X (Extended MSI):
┌────────────────────────────────────┐
│  MSI增强版                          │
│                                    │
│  MSI-X表(设备内存映射区域):      │
│  ┌────────┬──────────┬─────────┐  │
│  │ Entry  │ 地址     │ 数据    │  │
│  ├────────┼──────────┼─────────┤  │
│  │   0    │0xFEE00020│ Vector1 │  │
│  │   1    │0xFEE00040│ Vector2 │  │
│  │  ...   │   ...    │  ...    │  │
│  │  2047  │0xFEE00xxx│ VectorN │  │
│  └────────┴──────────┴─────────┘  │
│                                    │
│  特性:                             │
│  - 最多2048个中断向量                │
│  - 每个中断独立配置                  │
│  - 支持CPU亲和性                    │
│  - 屏蔽位(单独控制每个中断)         │
│                                    │
│  应用:高性能网卡(每队列一个中断)   │
└────────────────────────────────────┘

中断亲和性配置:
┌────────────────────────────────────┐
│  将设备中断绑定到特定CPU核心        │
│                                    │
│  示例(网卡多队列):               │
│  ┌──────────┐                      │
│  │ 网卡     │                      │
│  │ ┌──┐┌──┐│                      │
│  │ │Q0││Q1││                      │
│  │ └┬─┘└┬─┘│                      │
│  └──┼───┼──┘                      │
│     │   │                         │
│    中断 中断                        │
│     0   1                         │
│     │   │                         │
│  ┌──▼───▼───────────┐             │
│  │  CPU             │             │
│  │ ┌───┐ ┌───┐     │             │
│  │ │CPU0│ │CPU1│   │             │
│  │ │IRQ0│ │IRQ1│   │             │
│  │ └───┘ └───┘     │             │
│  └──────────────────┘             │
│                                   │
│  /proc/irq/N/smp_affinity 配置   │
└───────────────────────────────────┘

4.2 中断处理流程

┌─────────────────────────────────────────────────────────────┐
│              Linux中断处理(Interrupt Handling)              │
└─────────────────────────────────────────────────────────────┘

中断处理分层:
┌────────────────────────────────────────┐
│  硬件中断发生                           │
│    │                                   │
│    ▼                                   │
│  1. CPU保存现场                        │
│     - 保存寄存器                        │
│     - 切换到中断栈                      │
│    │                                   │
│    ▼                                   │
│  2. 执行中断向量表ISR                   │
│     do_IRQ()                           │
│    │                                   │
│    ▼                                   │
│  3. 上半部处理 (Top Half)              │
│     ┌─────────────────────────────┐   │
│     │  - 快速、原子操作             │   │
│     │  - 禁止中断                   │   │
│     │  - 清除中断标志               │   │
│     │  - 读取设备状态               │   │
│     │  - 调度下半部                 │   │
│     └─────────────────────────────┘   │
│    │                                   │
│    ▼                                   │
│  4. 恢复现场返回                       │
│    │                                   │
│    ▼                                   │
│  5. 下半部处理 (Bottom Half)           │
│     ┌─────────────────────────────┐   │
│     │  可选机制:                   │   │
│     │  - Softirq (软中断)          │   │
│     │  - Tasklet                   │   │
│     │  - Workqueue (工作队列)      │   │
│     │                              │   │
│     │  - 慢速、可睡眠               │   │
│     │  - 允许中断                   │   │
│     │  - 复杂数据处理               │   │
│     │  - 唤醒应用进程               │   │
│     └─────────────────────────────┘   │
└────────────────────────────────────────┘

示例:网卡接收中断
┌────────────────────────────────────────┐
│  中断上半部(硬中断上下文):           │
│                                        │
│  irqreturn_t nic_interrupt(            │
│      int irq, void *dev_id)            │
│  {                                     │
│      // 禁用设备中断                    │
│      disable_device_interrupts();      │
│                                        │
│      // 读取中断状态                    │
│      status = read_status_register();  │
│                                        │
│      // 调度软中断处理                  │
│      napi_schedule(&napi);             │
│                                        │
│      return IRQ_HANDLED;               │
│  }                                     │
│                                        │
│  执行时间:<10μs                        │
└────────────────────────────────────────┘

┌────────────────────────────────────────┐
│  中断下半部(软中断上下文):           │
│                                        │
│  int nic_poll(struct napi *napi,       │
│               int budget)              │
│  {                                     │
│      int processed = 0;                │
│                                        │
│      // 循环处理接收队列                │
│      while (processed < budget) {      │
│          skb = receive_packet();       │
│          if (!skb) break;              │
│                                        │
│          netif_receive_skb(skb);       │
│          processed++;                  │
│      }                                 │
│                                        │
│      // 重新启用中断                    │
│      if (processed < budget) {         │
│          enable_device_interrupts();   │
│      }                                 │
│                                        │
│      return processed;                 │
│  }                                     │
│                                        │
│  执行时间:可长(处理多个包)            │
└────────────────────────────────────────┘

NAPI (New API) 轮询模式:
┌────────────────────────────────────────┐
│  低负载:中断驱动                       │
│  ┌────┐  ┌────┐  ┌────┐               │
│  │ 包 │  │ 包 │  │ 包 │  每个包一次中断│
│  └─┬──┘  └─┬──┘  └─┬──┘               │
│    │中断   │中断   │中断               │
│    ▼       ▼       ▼                  │
│                                        │
│  高负载:轮询模式                       │
│  ┌────┬────┬────┬────┬────┐           │
│  │ 包 │ 包 │ 包 │ 包 │ 包 │  批量处理  │
│  └─┬──┴────┴────┴────┴────┘           │
│    │仅一次中断,后续轮询                │
│    ▼                                   │
│                                        │
│  自适应:根据负载切换模式                │
└────────────────────────────────────────┘

5. I/O虚拟化

5.1 SR-IOV技术

┌─────────────────────────────────────────────────────────────┐
│         SR-IOV (Single Root I/O Virtualization)              │
└─────────────────────────────────────────────────────────────┘

无SR-IOV(传统虚拟化):
┌────────────────────────────────────────┐
│  VM1      VM2      VM3                 │
│   │        │        │                  │
│   └────────┼────────┘                  │
│            │                           │
│            ▼                           │
│      ┌──────────┐                      │
│      │ Hypervisor│  软件模拟/半虚拟化  │
│      │  (QEMU)  │                      │
│      └─────┬────┘                      │
│            │                           │
│            ▼                           │
│       ┌─────────┐                      │
│       │ 物理网卡 │                      │
│       └─────────┘                      │
│                                        │
│  问题:                                 │
│  - 性能开销大(上下文切换)              │
│  - 延迟高                               │
│  - CPU占用高                            │
└────────────────────────────────────────┘

SR-IOV架构:
┌────────────────────────────────────────────────────┐
│  VM1         VM2         VM3         Hypervisor    │
│   │           │           │              │         │
│   │           │           │              │         │
│  VF1         VF2         VF3            PF         │
│   │           │           │              │         │
│   └───────────┴───────────┴──────────────┘         │
│                      │                             │
│                      ▼                             │
│           ┌──────────────────────┐                 │
│           │   物理网卡(SR-IOV)    │                 │
│           │                      │                 │
│           │  ┌────────────────┐  │                 │
│           │  │ PF (Physical   │  │  完整功能       │
│           │  │    Function)   │  │  (管理/配置)    │
│           │  └────────────────┘  │                 │
│           │                      │                 │
│           │  ┌───┐┌───┐┌───┐    │                 │
│           │  │VF1││VF2││VF3│    │  轻量级副本     │
│           │  └───┘└───┘└───┘    │  (仅数据路径)   │
│           │   ...最多256个VF     │                 │
│           └──────────────────────┘                 │
│                                                    │
│  优势:                                             │
│  - 接近原生性能(直通)                             │
│  - 低延迟                                           │
│  - 硬件隔离                                         │
└────────────────────────────────────────────────────┘

PF vs VF功能对比:
┌─────────────────────┬──────┬──────┐
│ 功能                │  PF  │  VF  │
├─────────────────────┼──────┼──────┤
│ 数据发送/接收        │  ✓   │  ✓   │
│ 配置寄存器访问       │  ✓   │  限制 │
│ 中断                │  ✓   │  ✓   │
│ DMA                 │  ✓   │  ✓   │
│ 创建/销毁VF          │  ✓   │  ✗   │
│ 全局配置            │  ✓   │  ✗   │
│ 固件更新            │  ✓   │  ✗   │
└─────────────────────┴──────┴──────┘

配置SR-IOV:
# 启用VF
echo 4 > /sys/class/net/eth0/device/sriov_numvfs

# 查看VF
lspci | grep Virtual

# 将VF分配给VM(libvirt)
<interface type='hostdev'>
  <source>
    <address type='pci' domain='0x0000'
             bus='0x05' slot='0x10' function='0x1'/>
  </source>
</interface>

6. I/O性能测试

6.1 PCIe性能测试

bash
#!/bin/bash
# PCIe设备性能测试

echo "========== PCIe设备信息 =========="
# 查看所有PCIe设备
lspci -vvv | grep -E "LnkCap|LnkSta" | head -20

echo -e "\n========== NVMe设备PCIe信息 =========="
# 查看NVMe设备的PCIe链路状态
for dev in /dev/nvme*n1; do
    if [ -e "$dev" ]; then
        echo "=== $dev ==="
        nvme id-ctrl $dev | grep -E "vid|ssvid"

        # PCIe链路速度
        dev_pci=$(readlink -f /sys/block/$(basename $dev)/device)
        echo "PCIe Gen: $(cat $dev_pci/current_link_speed 2>/dev/null)"
        echo "PCIe Width: $(cat $dev_pci/current_link_width 2>/dev/null)"
    fi
done

echo -e "\n========== 网卡PCIe信息 =========="
# 查看网卡PCIe配置
for nic in /sys/class/net/*/device; do
    if [ -e "$nic/current_link_speed" ]; then
        nicname=$(basename $(dirname $nic))
        echo "=== $nicname ==="
        echo "Speed: $(cat $nic/current_link_speed)"
        echo "Width: x$(cat $nic/current_link_width)"
    fi
done

echo -e "\n========== PCIe带宽测试(理论值)=========="
# 计算理论带宽
# PCIe 3.0 x4 = 3.94 GB/s
# PCIe 4.0 x4 = 7.88 GB/s

6.2 中断性能分析

bash
#!/bin/bash
# 中断性能分析脚本

echo "========== 中断统计 =========="
# 查看中断计数
cat /proc/interrupts | head -30

echo -e "\n========== 各CPU中断分布 =========="
# 显示每个CPU的总中断数
mpstat -P ALL 1 5 | grep -E "CPU|all"

echo -e "\n========== 软中断统计 =========="
# 查看软中断
cat /proc/softirqs

echo -e "\n========== 高频中断设备 =========="
# 找出中断最频繁的设备
watch -n 1 'cat /proc/interrupts | sort -k2 -rn | head -10'

echo -e "\n========== 中断亲和性检查 =========="
# 检查网卡中断亲和性
for irq in $(grep eth0 /proc/interrupts | cut -d: -f1); do
    echo "IRQ $irq: CPU mask = $(cat /proc/irq/$irq/smp_affinity 2>/dev/null)"
done

echo -e "\n========== 优化中断亲和性 =========="
# 示例:将网卡队列中断绑定到不同CPU
# 假设eth0有4个队列
queue=0
for irq in $(grep eth0-TxRx /proc/interrupts | cut -d: -f1); do
    cpu_mask=$(printf "%x" $((1 << queue)))
    echo $cpu_mask > /proc/irq/$irq/smp_affinity
    echo "IRQ $irq绑定到CPU $queue"
    ((queue++))
done

6.3 I/O性能监控

python
#!/usr/bin/env python3
"""
I/O系统性能监控脚本
"""

import os
import time
import subprocess

def monitor_interrupts(duration=10):
    """监控中断速率"""
    print("=== 中断速率监控 ===")

    # 读取初始值
    with open('/proc/interrupts') as f:
        lines1 = f.readlines()

    time.sleep(duration)

    # 读取结束值
    with open('/proc/interrupts') as f:
        lines2 = f.readlines()

    # 计算增量
    print(f"\n{duration}秒内中断增量(Top 10):")
    diffs = []

    for l1, l2 in zip(lines1[1:], lines2[1:]):
        cols1 = l1.split()
        cols2 = l2.split()

        if len(cols1) > 1 and cols1[0].endswith(':'):
            irq = cols1[0][:-1]
            # 累加所有CPU的中断数
            try:
                total1 = sum(int(x) for x in cols1[1:] if x.isdigit())
                total2 = sum(int(x) for x in cols2[1:] if x.isdigit())
                diff = total2 - total1
                if diff > 0:
                    desc = ' '.join(cols2[len([x for x in cols2 if x.isdigit()]):])
                    diffs.append((irq, diff, desc))
            except:
                pass

    diffs.sort(key=lambda x: x[1], reverse=True)
    for irq, count, desc in diffs[:10]:
        rate = count / duration
        print(f"  IRQ {irq:>4}: {rate:>10.0f} /秒  {desc[:50]}")

def monitor_pcie_errors():
    """监控PCIe错误"""
    print("\n=== PCIe错误检查 ===")

    try:
        result = subprocess.run(
            ['lspci', '-vvv'],
            capture_output=True,
            text=True
        )

        for line in result.stdout.split('\n'):
            if 'CorrErr' in line or 'UncErr' in line or 'Fatal' in line:
                print(f"  {line.strip()}")

    except:
        print("需要安装pciutils")

def monitor_dma_usage():
    """监控DMA使用情况"""
    print("\n=== DMA缓冲区使用 ===")

    try:
        with open('/proc/meminfo') as f:
            for line in f:
                if 'Bounce' in line or 'DMA' in line:
                    print(f"  {line.strip()}")
    except:
        pass

def monitor_io_metrics():
    """监控I/O指标"""
    print("\n=== I/O设备指标 ===")

    try:
        result = subprocess.run(
            ['iostat', '-x', '1', '2'],
            capture_output=True,
            text=True
        )
        print(result.stdout)
    except:
        print("需要安装sysstat")

def check_msi_capability():
    """检查设备MSI/MSI-X能力"""
    print("\n=== MSI/MSI-X支持情况 ===")

    try:
        result = subprocess.run(
            ['lspci', '-vvv'],
            capture_output=True,
            text=True
        )

        current_device = None
        for line in result.stdout.split('\n'):
            if line and not line.startswith('\t'):
                current_device = line.split()[0]
            elif 'MSI-X: Enable+' in line or 'MSI: Enable+' in line:
                print(f"  {current_device}: {line.strip()}")

    except:
        print("需要安装pciutils")

def main():
    """主函数"""
    print("I/O系统性能监控")
    print("=" * 60)

    if os.geteuid() != 0:
        print("警告:部分功能需要root权限")
        print()

    # 中断监控
    monitor_interrupts(duration=5)

    # PCIe错误
    monitor_pcie_errors()

    # DMA使用
    monitor_dma_usage()

    # I/O指标
    monitor_io_metrics()

    # MSI能力
    check_msi_capability()

    print("\n" + "=" * 60)
    print("监控完成")

if __name__ == "__main__":
    main()

7. 学习资源与总结

7.1 关键要点总结

┌─────────────────────────────────────────────────────────────┐
│                  I/O系统核心概念                              │
└─────────────────────────────────────────────────────────────┘

1. 总线演进
   ├─ ISA → PCI → PCIe
   ├─ 并行 → 串行点对点
   ├─ 共享总线 → 独占通道
   └─ PCIe 5.0: 63GB/s (x16)

2. PCIe协议
   ├─ 分层架构:事务层/链路层/物理层
   ├─ TLP数据包传输
   ├─ 通道配置:x1/x4/x8/x16
   └─ 编码效率:128b/130b

3. DMA机制
   ├─ 解放CPU(无需参与数据传输)
   ├─ Scatter-Gather(分散聚集)
   ├─ IOMMU地址转换和隔离
   └─ Coherent vs Streaming

4. 中断处理
   ├─ Legacy → MSI → MSI-X
   ├─ 上半部(快速)+ 下半部(慢速)
   ├─ NAPI轮询模式
   └─ 中断亲和性优化

5. I/O虚拟化
   ├─ SR-IOV:硬件虚拟化
   ├─ PF vs VF
   ├─ 接近原生性能
   └─ 硬件隔离

6. 性能优化
   ├─ PCIe链路速度检查
   ├─ 中断均衡分布
   ├─ IOMMU优化
   └─ NUMA本地化
└─────────────────────────────────────────────────────────────┘

下一步:学习GPU计算架构,理解CUDA编程和并行计算原理。

文件大小:约28KB 最后更新:2024年

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布