本页面讨论内联和非内联调用的性能问题 由驱动程序调度程序执行。
了解 内嵌和非内嵌调用 优化 Fuchsia 的驾驶员响应能力和整体系统性能。 本页列出了条件,其中 不能以内嵌方式进行调用,这也会影响性能。 此外,它还提供 用于调查问题的调试方法 非内嵌调用。
内嵌和非内嵌调用
当调度员需要“呼叫驱动程序”时( 代表驱动程序在线程上运行工作),调度程序首先 确定调用是否可以内联。如果不进行内联 相应通话安排在稍晚的时间点。
这些调用之间的主要区别如下:
- 内嵌:调度程序会立即调用驱动程序。来自 发送器在接收器收到后未返回到运行时循环 (见图 1)。
- 非内嵌:调度程序将调用安排在未来的时间发生 运行循环的迭代(参见图 2)。
内联调用比非内联调用更高效。例如, 内联单向通道调用大约需要 2 微秒,而非内联 单向信道调用最长可能需要 10 微秒。
图 1. 内嵌调用的流程。
图 2. 非内嵌调用的流程。
适用于非内嵌调用的条件
如果出现以下任一情况,调度程序都不会进行内联调用 适用条件:
调度程序允许屏蔽调用,但发送者不允许。
如果目标调度程序设置了 已设置
ALLOW_SYNC_CALLS
选项,但发件人 则不可以。这是为了防止阻塞非阻塞 调度程序。调度程序已同步,且未处于空闲状态。
此条件仅适用于 同步调度程序。调用 驱动程序,则驱动程序运行时会检查调度程序是否处于空闲状态。 如果未空闲,则不会进行内联调用,以避免调用 并行调用。
调用来自不受驱动程序运行时管理的线程。
派生驱动程序后,线程不受驱动程序运行时管理 自己的线程,例如使用
std::thread
或thread_create
方法。与 FIDL 接收端关联的频道尚未准备就绪。
FIDL 使用通道(Zircon)发送和接收消息 信道或驱动程序传输信道。为了接收消息,需要等待 需要由 FIDL 层在信道上注册, (通过 FIDL 绑定控制背景)。如果在该时间之前未记录到等待时间 则调度程序无法使调用内联。
系统会将通话视为可重入。
在图 3 中,当驾驶员 A 向收到 B 的驾驶员 B 发送 FIDL 请求时, 虽然驾驶员 B 会立即回复驾驶员 A,但这条消息是 视为司机 A 的可重赛者。在这种情况下,调度程序 对于驾驶员 A 进行非内嵌调用,以发送来自驾驶员 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