【问题标题】:Performance Read() and Write() to/from Linux SKB's与 Linux SKB 的性能 Read() 和 Write()
【发布时间】:2017-12-11 08:10:08
【问题描述】:

基于标准 Linux 系统,其中有一个用户区应用程序和内核网络堆栈。我读到将帧从用户空间移动到内核空间(反之亦然)在 CPU 周期方面可能会很昂贵。

我的问题是,

  1. 为什么?并且正在向一个方向移动框架(即从用户到 内核)具有更高的影响。
  2. 另外,当你 进入基于 TAP 的界面。由于框架仍将继续 用户/内核空间之间。是否存在空间问题,或者是否存在某种形式的零拷贝?

【问题讨论】:

  • 系统调用很昂贵。复制(从/到用户空间)相对便宜。
  • @wildplasser 好的,那么你什么时候使用系统调用?
  • 仅供参考:read()write() 是系统调用。

标签: linux tcp kernel


【解决方案1】:

在线解决问题:


为什么?并且正在向一个方向移动框架(即从用户到 kernel) 的影响更大。

Moving to/from user/kernel spaces is expensive 因为操作系统必须:

  • 验证复制操作的指针。
  • 传输实际数据。
  • 承担在用户/内核模式之间转换所涉及的通常成本。

对此有一些例外,例如,如果您的驱动程序实现了strategy such as "page flipping",它有效地重新映射内存块/页,以便用户空间应用程序可以访问它。这与零复制操作“足够接近”。

With respect to copy_to_user/copy_from_user performance, the performance of the two functions is apparently comparable.


此外,当您进入基于 TAP 的界面时,情况有何不同。作为 框架仍将在用户/内核空间之间移动。做空间 存在问题,或者是否存在某种形式的零拷贝?

对于基于 TUN/TAP 的接口,同样的注意事项也适用,除非您使用某种 DMA、页面翻转等;逻辑。

【讨论】:

    【解决方案2】:

    上下文切换

    将帧从用户空间移动到内核空间称为上下文切换,通常由系统调用(调用int 0x80中断)引起。

    • 发生中断,进入内核空间;
    • 当中断发生时,操作系统会将所有寄存器的值存储到线程的内核堆栈中:dsesfseaxcr3等等
    • 然后像函数调用一样跳转到IRQ处理程序;
    • 通过一些常见的IRQ执行路径,通过某种算法选择下一个线程运行;
    • 从下一个线程加载运行时信息(所有寄存器);
    • 返回用户空间;

    正如我们所见,我们在将帧移入/移出内核时会做很多工作,这比简单的函数调用(只需设置ebpespeip)要多得多。这就是为什么这种行为相对耗时。

    虚拟设备

    作为虚拟网络设备,写入TAP与写入/dev/xxx没有区别。

    如果你写到 TAP,os 会像上面的描述一样被中断,然后它会将你的参数复制到内核并阻塞你当前的线程(阻塞 IO)。内核驱动线程会以某种方式(例如消息队列)被通知接收参数并使用它。

    在 Andorid 中,存在一些zero-copy system call,在我的演示实现中,这可以通过用户和内核之间的地址转换来完成。因为内核和用户线程不共享相同的地址空间,用户线程的数据可能会改变,我们通常将数据复制到内核中。所以如果我们满足条件,我们就可以避免复制:

    • 必须阻止此系统调用,即数据不会更改;
    • 通过页表在地址之间进行转换,即内核可以引用正确的数据;

    代码

    以下是我的demo os中的代码,有兴趣的可以详细了解一下这个问题:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-27
      • 2019-06-30
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 2019-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多