Post

CS61C|Lec18-IO

CS61C|Lec18-IO

CPU与外界交互的方式是通过I/O接口

CS61C|Lec18-IO-20250122.png

如何实现I/O接口呢

方法一:

使用特殊的输入输出指令和对应的硬件设计

方法二:

内存映射I/O(Memory-Mapped I/O)

  • 定义:将I/O设备的寄存器映射到处理器的地址空间中,形成一个特定的地址范围用于I/O操作。

  • 操作方式

    • 使用普通的加载(load)和存储(store)指令(例如 lw 和 sw)访问I/O设备。

    • 通过访问特定的地址来与I/O设备进行通信。

  • 优点

    • 统一的地址空间,简化了指令集(只需要加载和存储指令)。

    • 可以利用现有的内存访问机制,简化了硬件设计。

    • 更容易实现DMA(直接内存访问)等高级特性。

  • 缺点

    • 可能会消耗一部分内存地址空间,限制可用内存的总量。

    • 需要处理I/O设备的状态和控制寄存器,可能会增加复杂性。

内存映射I/O

一些特殊的地址用来干一些特殊的事情,比如:

CS61C|Lec18-IO-20250122-1.png

轮询(Polling)

  1. 设备寄存器的作用

I/O 设备通常会有两个主要寄存器:

  • 控制寄存器(Control Register):表示设备是否准备好进行读写操作。类似于一个信号员,它告诉处理器设备当前的状态,是否可以进行数据传输。

  • 数据寄存器(Data Register):存储设备上的数据,处理器可以从这个寄存器中读取输入数据,或将数据写入其中以传送给设备。

  1. 轮询过程

轮询的过程就是处理器不断检查控制寄存器的状态,直到设备准备好,具体步骤如下:

  1. 读取控制寄存器:处理器会反复读取控制寄存器,检查“就绪位”(Ready bit)的状态。

    • 当“就绪位”为 0 时,表示设备还未准备好,处理器会继续等待。

    • 当“就绪位”从 0 变为 1 时,表示设备已经准备好,处理器可以进行接下来的操作。

  2. 执行 I/O 操作

    • 如果是输入操作(读取数据),处理器从数据寄存器读取数据。

    • 如果是输出操作(写入数据),处理器将数据写入数据寄存器

  3. 重置控制寄存器:I/O 操作完成后,设备会将控制寄存器的“就绪位”重置为 0,表示当前操作已完成,处理器需要等待下一次操作。

轮询的例子

  1. 输入(从键盘读数据)
1
2
3
4
5
6
lui t0, 0x7ffff  # 加载 I/O 地址 7ffff000 到寄存器 t0
Waitloop: 
  lw t1, 0(t0)    # 读取控制寄存器的值到 t1
  andi t1, t1, 0x1 # 检查就绪位 (Ready bit),即 t1 & 1
  beq t1, zero, Waitloop # 如果就绪位为 0,继续等待
lw a0, 4(t0)     # 读取数据寄存器中的数据到 a0
  • lui t0, 0x7ffff:将 I/O 设备的基地址 0x7ffff000 加载到寄存器 t0。

  • Waitloop:轮询等待环节。在循环中,通过 lw t1, 0(t0) 从 I/O 控制寄存器读取设备状态,检查其是否已经准备好。使用 andi t1, t1, 0x1 提取出“就绪位”。

  • beq t1, zero, Waitloop:如果“就绪位”为0(设备未准备好),继续在 Waitloop 循环等待。

  • lw a0, 4(t0):当设备准备好后,从数据寄存器读取键盘输入,保存到寄存器 a0 中。

为什么要用lui加载地址?

  1. 输出操作(向显示器写入数据)
1
2
3
4
5
6
lui t0, 0x7ffff  # 加载 I/O 地址 7ffff000 到寄存器 t0
Waitloop: 
  lw t1, 8(t0)    # 读取控制寄存器的值到 t1
  andi t1, t1, 0x1 # 检查就绪位 (Ready bit),即 t1 & 1
  beq t1, zero, Waitloop # 如果就绪位为 0,继续等待
sw a1, 12(t0)    # 将 a1 中的数据写入显示设备的数据寄存器
  • lui t0, 0x7ffff:同样地,将 I/O 设备的基地址加载到 t0。

  • Waitloop:同样通过轮询读取控制寄存器 lw t1, 8(t0),等待显示设备准备好接收数据。

  • sw a1, 12(t0):当设备就绪时,将 a1 寄存器中的数据写入显示设备的数据寄存器 12(t0)。

轮询的开销

假设一个处理器的参数如下

  1. 1 GHz 时钟频率
  • 这意味着处理器每秒可以执行 10亿次(10^9)时钟周期
  1. 每次轮询操作需要 400 个时钟周期
  • 包含调用轮询例程、检查设备状态以及返回。

问题:在给定情况下,处理器在轮询上花费的时间百分比是多少?

我们将以下场景代入计算:

轮询鼠标

  • 假设轮询的设备是鼠标,轮询频率为 每秒 30 次,为了确保不会漏掉鼠标的任何移动(避免光标在屏幕上的卡顿)。
  1. 每秒钟轮询次数:

每秒轮询 30 次,因此处理器每秒执行 30 次轮询操作。

  1. 每次轮询操作的时钟周期数:

每次轮询需要 400 个时钟周期,因此每秒轮询所花费的时钟周期总数为:

$30 \, \text{次/秒} \times 400 \, \text{时钟周期/次} = 12000 \, \text{时钟周期/秒}$

  1. 处理器每秒执行的总时钟周期:

处理器的时钟频率为 1 GHz,即处理器每秒可以执行 10^9(十亿)个时钟周期。

  1. 轮询开销的时间百分比: 我们需要计算在总时钟周期中,轮询所占的比例:

$\frac{12000 \, \text{时钟周期/秒}}{10^9 \, \text{时钟周期/秒}} \times 100\% = 0.0012\%$

轮询硬盘

轮询硬盘的频率 = $\frac{16 \, \text{MB/s}}{16 \, \text{B/轮询}} = 1,000,000 \, \text{轮询/秒} \, \text{(1百万次轮询/秒)}$

步骤 2:轮询所需时钟周期

每次轮询需要 400 个时钟周期。因此,轮询硬盘每秒所需的总时钟周期为:

$1,000,000 \, \text{轮询/秒} \times 400 \, \text{时钟周期/轮询} = 400,000,000 \, \text{时钟周期/秒}$

步骤 3:计算处理器时间百分比

处理器的时钟频率为 1 GHz,即 10亿时钟周期/秒。轮询硬盘所需的时钟周期占处理器总时钟周期的百分比为:

$\frac{400,000,000 \, \text{时钟周期/秒}}{1,000,000,000 \, \text{时钟周期/秒}} \times 100\% = 40\%$

轮询硬盘占用了处理器 40% 的时间,显然这是不可接受的,因为这意味着处理器的大量时间都花费在等待 I/O 操作上,而不能有效执行其他任务。此外,这个例子也指出了数据以 小块传输 形式处理的低效性,这也是问题的一部分。

I/O中断

轮询效率很低,因为不管有没有数据传输过来,我们都要去检查控制位。就像你家在开派对,你设置了一个计时器,隔一段时间就要去看看门口有没有人要进来一样低效。所以我们应该安装一个门铃!

那么在计算机中的门铃就是中断。

  1. 中断的工作机制

    • 中断定义:当I/O设备准备好或者需要处理时,它向处理器发出一个信号,叫做中断。处理器会暂停当前程序的执行,转到操作系统的中断处理程序(trap handler)。

    • 优势:

      • 没有I/O活动时,处理器不会浪费时间。

      • 中断只在必要时才触发,有效利用资源。

    • 缺点:在频繁的I/O活动下,过多的中断会导致高昂的成本,比如影响缓存、虚拟内存的使用以及状态的保存和恢复。

  2. 适合中断的场景

  • 低数据速率设备(如鼠标、键盘):

  • 适合使用中断,因为这些设备的数据量很小,中断的开销也低。

  • 可以使用定时器中断来轮询,但这种情况下中断机制足够高效。

  • 高数据速率设备(如网络、硬盘):

  • 初始时可以使用中断来检测数据是否到达。

  • 一旦有大量数据到来,直接内存访问(DMA) 可以介入,将数据直接传输到内存,避免频繁的中断和处理器干预。

  1. 直接内存访问(DMA Direct Memory Access)
  • 在大量数据传输时,中断机制会切换为DMA,以减少处理器干预。DMA 允许数据在I/O设备和内存之间直接传输,从而提高效率。

Direct Memory Access(DMA)

DMA (Direct Memory Access) 允许 I/O 设备直接与主存进行数据交换,而无需处理器的过多干预。这极大提高了高数据速率设备的效率,尤其是在大量数据传输时。下面是 DMA 的工作机制及其关键组成部分:

  1. DMA 引擎
  • DMA 引擎是一个专门的硬件组件,它负责管理 I/O 设备和主存之间的数据传输。

  • DMA 引擎通过一组寄存器与 CPU 进行交互,这些寄存器由 CPU 设置,指定传输的详细信息。

  1. DMA 寄存器的功能
  • 内存地址(Memory address):指定数据要存放或读取的内存地址。

  • 传输字节数(# of bytes):指定需要传输的数据量(以字节为单位)。

  • I/O 设备号(I/O device #):指示哪个设备将进行数据传输。

  • 传输方向(Direction of transfer):指定是从 I/O 设备向内存传输数据,还是从内存向 I/O 设备传输数据。

  • 传输单元(Unit of transfer):指定每次传输的数据块大小。

  • 传输突发量(Amount to transfer per burst):定义每次传输的突发量,即在一次传输周期内移动的最大数据量。

  1. DMA 的工作流程

  2. CPU 设置 DMA:CPU 首先配置 DMA 引擎的寄存器,指定数据传输的参数(内存地址、传输字节数等)。

  3. DMA 传输:DMA 引擎接管传输过程,直接在内存和 I/O 设备之间进行数据传输,而不需要处理器的干预。

  4. 完成传输:传输完成后,DMA 通知处理器,表明数据传输已经完成。

CS61C|Lec18-IO-20250122-2.png

  1. DMA 的优势
  • 降低处理器负载:DMA 减少了处理器在大数据传输过程中的干预,腾出处理器资源去处理其他任务。

  • 提升传输效率:直接在内存和 I/O 设备之间进行数据传输,避免了轮询和过多中断造成的开销。

这种机制尤其适合像硬盘、网络等需要传输大量数据的设备,极大提高了系统性能。

打个比方,你开个面粉厂,每天要给不同大小的货车搬不同量的面粉放在货车上,后来干大了,你觉得你有更重要的事要做,所以你找了个傻子小弟,小弟只知道你发出的指令,从哪搬,搬多少,你说了他就照这个办。

DMA 传输的两种情况:输入与输出

  1. DMA:输入数据的流程

  2. 设备发出中断信号:当设备有数据准备好时,它向 CPU 发送中断信号。

  3. CPU 响应中断并启动传输:CPU 响应中断信号,指示 DMA 引擎或设备将数据放置在特定的内存地址。

  4. DMA 进行传输:DMA 引擎或设备负责实际的数据传输,期间 CPU 可以继续执行其他任务。

  5. 传输完成,中断 CPU:当传输完成时,DMA 或设备再次中断 CPU,通知传输已完成。

  6. DMA:输出数据的流程

  7. CPU 决定开始传输:CPU 检查外部设备是否准备好接收数据。

  8. CPU 开始传输:CPU 指示 DMA 引擎或设备,告知特定内存地址有数据准备好传输。

  9. DMA 进行传输:DMA 引擎或设备处理数据传输,CPU 仍然可以执行其他任务。

  10. 传输完成,中断 CPU:DMA 或设备传输完成后,再次中断 CPU,通知任务完成。

DMA 引擎插入内存层次结构中的问题

DMA 引擎在内存层次结构中的插入位置会对系统性能产生影响,以下是两个极端位置:

  1. 在 L1 缓存和 CPU 之间
  • 优点:这种方式可以保证数据的一致性(缓存一致性问题会自动解决)。

  • 缺点:可能会污染 CPU 的工作集,将传输的数据加载到 CPU 缓存中,导致缓存失效和性能下降。

  1. 在最后一级缓存和主内存之间
  • 优点:不会影响 CPU 的缓存,不会污染缓存数据。

  • 缺点:需要手动管理数据一致性,处理起来较为复杂。

This post is licensed under CC BY 4.0 by the author.