驱动程序调度程序性能

本页介绍了驱动程序调度程序进行的内嵌调用和非内嵌调用的性能方面。

了解内嵌调用和非内嵌调用之间的差异有助于优化驱动程序的响应能力和 Fuchsia 的整体系统性能。本页介绍了无法内嵌调用的条件,以及这些条件对性能的影响。此外,它还提供了一种用于调查非内嵌调用的调试技术

内嵌调用和非内嵌调用

当调度程序需要“调用驱动程序”(即代表驱动程序在线程上运行工作)时,调度程序会先确定是否可以内嵌调用。如果不内嵌,系统会在稍后的时间安排调用。

这两种调用之间的主要区别如下:

  • 内嵌:调度程序会立即调用驱动程序。接收器会接收来自发送方的请求,而无需返回到运行时循环(请参阅图 1)。
  • 非内嵌:调度程序会将调用安排在运行时循环的未来迭代中执行(请参阅图 2)。

内嵌调用比非内嵌调用更高效。例如,内嵌单向通道调用大约需要 2 微秒,而非内嵌单向通道调用最多可能需要 10 微秒。

内嵌通话流程

图 1. 内嵌调用的流程。

非内嵌调用流程

图 2. 非内嵌调用的流程。

非内嵌调用的条件

如果满足以下任一条件,调度程序不会将调用内嵌:

  • 调度程序允许屏蔽通话,但发件人不允许

    如果目标调度程序设置了 ALLOW_SYNC_CALLS 选项,但发送方调度程序未设置该选项,则调用不会内嵌。这是为了防止阻塞同一调用堆栈中的非阻塞调度程序。

  • 调度程序已同步且并非空闲状态

    此条件仅适用于同步调度程序。调用驱动程序时,驱动程序运行时会检查调度程序是否处于空闲状态。如果它不是空闲状态,则不会内嵌调用,以避免对驱动程序进行并行调用。

  • 调用来自不受驱动程序运行时管理的线程

    当驱动程序使用 std::threadthread_create 方法等方法生成自己的线程时,线程不会由驱动程序运行时管理。

  • 与 FIDL 接收端关联的通道未准备就绪

    FIDL 传输使用通道(Zircon 通道或驱动程序传输通道)发送和接收消息。为了接收消息,FIDL 层需要在通道上注册等待(由 FIDL 绑定在后台处理)。如果在收到消息时未注册等待,调度程序将无法使调用内嵌。

  • 该调用会被视为可重入

    在图 3 中,当驱动程序 A 向驱动程序 B 发送 FIDL 请求(该请求会按行接收),即使驱动程序 B 立即回复驱动程序 A,此消息也被视为对驱动程序 A 的重入。在这种情况下,Driver A 的调度程序会进行非内嵌调用,以发送 Driver B 的回复。

    无论调度程序为哪些驱动程序提供服务,重入检查都适用于调度程序。例如,如果驱动程序拥有两个调度程序,则在这两个调度程序之间发送和接收消息始终被视为可重入,并且无法内嵌。

  • 该调用是使用 Zircon 通道传输的 FIDL 请求

    只有驱动程序传输支持 FIDL 内嵌。与 Zircon 通道不同,驱动程序传输通道仅在进程中,并且允许在驱动程序传输通道逻辑中实现特殊的嵌入。

由于重入而导致的非内嵌调用流程

图 3. 由于重入而导致的非内嵌调用的流程。

调试非内嵌调用

fdf_env_dispatcher_dump 函数可帮助驱动程序作者调试某些调用未内嵌的原因。此函数会记录非内嵌调用的计数和原因,例如:

INFO: [my_driver.cc(212)] ---- Runtime Dispatcher Dump Begin ----
INFO: [my_driver.cc(212)] The current thread is not managed by the driver runtime.
INFO: [my_driver.cc(212)] Dispatcher to dump: TestBody (0x24a7614d4240) (driver 0x10)
INFO: [my_driver.cc(212)] Synchronized: true
INFO: [my_driver.cc(212)] Allow sync calls: false
INFO: [my_driver.cc(212)] State: running
INFO: [my_driver.cc(212)] Processed 5 requests, 3 were inlined
INFO: [my_driver.cc(212)] Reasons why requests were not inlined:
INFO: [my_driver.cc(212)] * The request would have been reentrant: 2 times
INFO: [my_driver.cc(212)] * Another thread was already dispatching a request: 1 times
INFO: [my_driver.cc(212)] No queued tasks

如需在开发期间调用此函数,您需要修改受限符号许可名单,并使用相应更改 OTA/刷写 Fuchsia 设备。