代码之家  ›  专栏  ›  技术社区  ›  Eric B

当CPU/内核被硬件中断淹没时,它是如何允许用户空间代码运行的?

  •  0
  • Eric B  · 技术社区  · 1 年前

    我了解到,当硬件中断发生时,CPU会将其寄存器保存到内存中,并立即从中断矢量表中运行相应的代码。考虑到这些HI几乎发生在每种类型的I/O操作和事件中,CPU怎么还能如此高效地处理所有这些HI并允许用户空间代码运行?或者,如果它不能跟上HI的处理,它如何允许用户空间代码不时运行?

    假设你正在玩一款在线射击游戏,你可以不断移动鼠标,按住多个键,每秒数千次接收和发送数据包,为每一帧更新屏幕,并从磁盘加载网格或将保存写入磁盘。这可能会导致每秒数万次,甚至数十万次HI。现在,对于每个HI,都应该运行一个指令段(比如说几十行指令)。这可能导致每秒运行数百万条代码指令,而这还没有考虑将CPU状态(寄存器、标志等)推送到内存并从内存中检索到每个模式切换所需的时间。。。

    最重要的是,CPU应该运行数万行用户代码来解释所有这些数据,并计算游戏机制、行为、碰撞、渲染等。

    那么CPU/内核如何确保用户空间代码也能运行呢?我可以想象,在我上面描述的场景中,用户空间代码根本没有时间运行,除非它有某种相反的硬件中断定时器。

    1 回复  |  直到 1 年前
        1
  •  1
  •   Peter Cordes    1 年前

    如果您确实有太多的硬件中断,以至于在处理完前一个中断之前,另一个中断处于挂起状态,那么用户空间代码可能只运行0或1指令,然后再被中断。因此,如果设备引发中断的速度快于CPU硬件+软件运行处理程序的速度,那么饥饿是可能的。

    我认为 Intel CPUs finish the oldest instruction in the ROB (reorder buffer) before taking an exception ,所以我认为 iret 在另一个中断挂起的情况下,用户空间不会完全耗尽这些CPU。不过,中断是可嵌套的:一个中断的处理程序可以被另一个中断中断。因此,随着多个设备产生大量中断,用户空间可能会 非常 CPU时间很少。(不同的ISAs有不同的机制,用于中断优先级和阻止优先级较低的中断,同时为优先级较高的中断提供服务,以及通知中断控制器您已经处理完这一中断,以便在设备再次发出或仍在发出其中断请求信号时,它可以并且应该再次发出中断请求信号。)

    如今的CPU速度在GHz范围内,并且能够在每个周期运行多个指令。(但现代x86 CPU在用户空间中的最后一条指令和中断处理程序中的第一条指令之间可能会停滞一到两百个周期,所以这并不便宜。)

    CPU也有多个核心,每个中断只需要由一个核心处理,而其他核心仍在工作。操作系统可能会配置一些东西,使来自一个设备的所有中断都由一个核心处理,来自另一设备的所有干扰都由另一个核心来处理,因此一些相关的代码和数据可能在缓存中很热。如果我看 /proc/interrupts 在我的Linux桌面上,我可以看到我的NVMe SSD实际上有9个队列,每个q1-q8的中断都由我的i7-6700k中的8个逻辑核心中的一个来处理(4c8t,带超线程的四核)。所有视频卡在一个核心上中断,所有以太网(e1000e驱动程序)在另一个核心中断。所有音频驱动程序在另一个内核上中断(处理视频驱动程序中断的内核的超线程兄弟,也许只是巧合。

    每秒数十万次的中断会产生一定的减速。键盘事件可以忽略不计;自动重复是在软件中完成的,而不是通过键盘重复发送按下和释放事件。它只是向媒体发送一个事件,并发布一个事件。GPU驱动程序将命令的缓冲区传递给GPU以供其读取。磁盘排队DMA工作,尽管读取完成时会中断。(也许还有一次写入。)但是很多文件访问都是由操作系统缓存的,只是过一段时间才会刷新到磁盘。读取已经在RAM中的文件不需要任何磁盘I/O。

    网卡是可能产生过多中断的设备,尤其是在具有10Gbit或100Gbit以太网的服务器(或工作站)上,尤其是多个此类链路上。以太网驱动程序的简单工作方式是每个数据包中断一次,而典型的非巨型帧只有大约1500字节,这是一个 大量 在这些链路速度下的中断。(即使是9k巨型帧也只能起到很大的作用)。

    因此,大多数操作系统中的现代网络硬件和驱动程序都支持轮询或批处理,只会在 n 数据包,或者在某个超时之后。驱动程序向设备提供一个指向内存的指针;硬件在传入数据包到达时将其写入存储器,因此不需要大量板载RAM来缓冲一批数据包。

    https://learn.microsoft.com/en-us/windows-hardware/drivers/network/interrupt-moderation 解释了Windows版本的中断调节。

    https://www.kernel.org/doc/html/next/networking/net_dim.html 记录了Linux版本:动态中断调节。以及内核API,网络驱动程序可以使用它来利用现有的代码,而不是单个驱动程序必须自己完成。

    我不确定是否有任何其他设备(和驱动程序),如NVMe SSD,通常会在高活动状态下切换到轮询(例如,每毫秒,或每几十或数百微秒)。这可能对I/O延迟更糟,但有助于吞吐量,因此对于具有大量I/O并行性的工作负载来说是个好主意。

    我想我读过USB外部硬盘驱动器通常 不能 以这种方式减少CPU负载(并且可能涉及每个扇区多个中断,因为USB大容量存储非常原始?),但支持USB连接SCSI(UASP)的存储可能更高效。(显然,这需要主板供应商支付许可费才能启用UASP,而不管实际需要什么硬件(如果有的话)。)这可能不是动态中断调节,但对于传输的相同数据量,命令排队和更少的CPU开销确实有助于传输速度和CPU负载。 https://www.tomshardware.com/reviews/usb-3-uas-turbo,3215-4.html / https://news.ycombinator.com/item?id=23741640