GXF 调度器
图中实体的执行由调度器以及与每个实体关联的调度项管理。调度器是负责协调图中定义的所有实体执行的组件。调度器通常跟踪图实体及其当前的执行状态,并在准备好执行时将它们传递给 nvidia::gxf::EntityExecutor
组件。下图描述了实体执行的流程。

图:实体执行序列
如图序图所示,调度器通过 nvidia::gxf::System::runAsync\_abi()
接口开始执行图实体,并持续此过程直到满足特定结束条件。单个实体可以有多个代码let。这些代码let按照它们在实体中定义的相同顺序执行。任何单个代码let执行失败都会停止所有实体的执行。当任何一个实体的调度项达到 NEVER
状态时,实体自然会从执行中取消调度。
调度项是用于定义实体执行就绪状态的组件。一个实体可以关联多个调度项,每个调度项使用 SchedulingCondition 表示实体的状态。
下表显示了使用 nvidia::gxf::SchedulingCondition
描述的 nvidia::gxf::SchedulingConditionType
的各种状态。
SchedulingConditionType | 描述 |
---|---|
NEVER | 实体将永远不再执行 |
READY | 实体已准备好执行 |
WAIT | 实体将来可能会执行 |
WAIT_TIME | 实体将在指定持续时间后准备好执行 |
WAIT_EVENT | 实体正在等待具有未知时间间隔的异步事件 |
调度器将死锁定义为当没有实体处于 READY
、WAIT\_TIME
或 WAIT\_EVENT
状态时的情况,这些状态保证将来某个时间点执行。这意味着所有实体都处于 WAIT
状态,调度器不知道它们是否会在将来达到 READY
状态。可以配置调度器,使其在使用 stop\_on\_deadlock
参数达到这种状态时停止,否则将轮询实体以检查它们中的任何一个是否已达到 READY
状态。max\_duration
配置参数可用于在指定的时间量过去后停止所有实体的执行,而与其状态无关。
GXF 目前支持两种类型的调度器
贪婪调度器
多线程调度器
这是一个基本的单线程调度器,它贪婪地测试调度项。它非常适合简单的用例和可预测的执行,但可能会产生大量的调度项执行开销,使其不适合大型应用程序。调度器需要一个时钟来跟踪时间。根据时钟的选择,调度器的执行方式会有所不同。如果使用实时时钟,调度器将实时执行。这意味着暂停执行——睡眠线程——直到周期性调度项再次到期。如果使用手动时钟,调度将“时间压缩”地发生。这意味着时间流被改变为立即连续执行代码let。
GreedyScheduler
维护处于 READY
、WAIT\_TIME
和 WAIT\_EVENT
状态的实体的运行计数。以下活动图描述了贪婪调度器调度实体的决策要点

图:贪婪调度器活动图
贪婪调度器配置
贪婪调度器从配置文件中获取以下参数
参数名称 | 描述 |
---|---|
clock | 调度器用于定义时间流的时钟。典型的选择是 RealtimeClock 或 ManualClock |
max_duration_ms | 调度器将执行的最长持续时间(以毫秒为单位)。如果未指定,调度器将运行直到完成所有工作。如果存在周期性项,则意味着应用程序将无限期运行 |
stop_on_deadlock | 如果禁用 stop_on_deadlock,则 GreedyScheduler 会不断轮询所有等待实体的状态,以检查它们中的任何一个是否已准备好执行。 |
示例用法 – 以下代码片段配置了一个指定了 ManualClock 选项的贪婪调度器。
name: scheduler
components:
- type: nvidia::gxf::GreedyScheduler
parameters:
max_duration_ms: 3000
clock: misc/clock
stop_on_deadlock: true
---
name: misc
components:
- name: clock
type: nvidia::gxf::ManualClock
多线程调度器更适合具有复杂执行模式的大型应用程序。调度器由一个调度器线程组成,该线程检查实体的状态,并将其分派到负责执行它们的工作线程池。工作线程在执行完成后将实体重新排队到分派队列中。可以使用 worker\_thread\_number
参数配置工作线程的数量。多线程调度器还管理一个专用的队列和线程来处理异步事件。以下活动图演示了多线程调度器实现的要点。

图:多线程调度器活动图
如图所示,当实体达到 WAIT\_EVENT
状态时,它会被移动到一个队列中,在其中等待接收事件完成通知。异步事件处理程序线程负责在接收到事件完成通知后将实体移动到调度器。调度器线程还维护处于 READY
、WAIT\_EVENT
和 WAIT\_TIME
状态的实体数量的运行计数,并使用这些统计信息来检查调度器是否已达到死锁。调度器还需要一个时钟组件来跟踪时间,它使用 clock
参数进行配置。
与贪婪调度器相比,多线程调度器更具资源效率,并且不会因不断轮询调度项的状态而产生任何额外的开销。check\_recession\_period\_ms
参数可用于配置调度器必须等待轮询处于 WAIT
状态的实体状态的时间间隔。
多线程调度器配置
多线程调度器从配置文件中获取以下参数
参数名称 | 描述 |
---|---|
clock | 调度器用于定义时间流的时钟。典型的选择是 RealtimeClock 或 ManualClock。 |
max_duration_ms | 调度器将执行的最长持续时间(以毫秒为单位)。如果未指定,调度器将运行直到完成所有工作。如果存在周期性项,则意味着应用程序将无限期运行。 |
check_recess_period_ms | 再次检查实体条件之前要休眠的持续时间 [ms]。这是当实体尚未准备好运行时,调度器将等待的最长持续时间。 |
stop_on_deadlock | 如果启用,当所有实体都处于等待状态,但没有周期性实体来打破僵局时,调度器将停止。当调度条件可以由外部参与者更改时,应禁用此功能,例如手动清除队列。 |
worker_thread_number | 线程数。 |
示例用法 – 以下代码片段配置了一个指定了工作线程数和最大持续时间的多线程调度器
name: scheduler
components:
- type: nvidia::gxf::MultiThreadScheduler
parameters:
max_duration_ms: 5000
clock: misc/clock
worker_thread_number: 5
check_recession_period_ms: 3
stop_on_deadlock: false
---
name: misc
components:
- name: clock
type: nvidia::gxf::RealtimeClock
Epoch 调度器用于在外部管理的线程中运行负载。每次运行称为一个 Epoch。调度器遍历所有已知处于活动状态的实体,并逐个执行它们。如果提供了 epoch 预算(以毫秒为单位),它将继续运行所有代码let,直到预算耗尽或没有代码let准备就绪。它可能会超出预算,因为它保证覆盖一个 epoch 中的所有代码let。如果未提供预算,它将遍历所有代码let 一次,并且仅执行一次。
Epoch 调度器从配置文件中获取以下参数
参数名称 | 描述 |
---|---|
clock | 调度器用于定义时间流的时钟。典型的选择是 RealtimeClock。 |
示例用法 – 以下代码片段配置了一个 Epoch 调度器
name: scheduler
components:
- name: clock
type: nvidia::gxf::RealtimeClock
- name: epoch
type: nvidia::gxf::EpochScheduler
parameters:
clock: clock
请注意,Epoch 调度器旨在从外部线程运行。runEpoch(float budget_ms);
可用于设置 budget_ms 并从外部线程运行调度器。如果指定的预算不是正数,则所有节点都将执行一次。
SchedulingTerm
定义了一个特定条件,实体使用该条件来通知调度器它何时准备好执行。GXF 目前支持各种调度项。
PeriodicSchedulingTerm
与 nvidia::gxf::PeriodicSchedulingTerm
关联的实体在以其 recess\_period
参数指定的周期性时间间隔后准备好执行。PeriodicSchedulingTerm
可以处于 READY
或 WAIT\_TIME
状态。
示例用法
- name: scheduling_term
type: nvidia::gxf::PeriodicSchedulingTerm
parameters:
recess_period: 50000000
CountSchedulingTerm
与 nvidia::gxf::CountSchedulingTerm
关联的实体将执行指定的次数,次数由其 count
参数指定。CountSchedulingTerm
可以处于 READY
或 NEVER
状态。当实体已执行 count
次时,调度项达到 NEVER
状态。
示例用法
- name: scheduling_term
type: nvidia::gxf::CountSchedulingTerm
parameters:
count: 42
MessageAvailableSchedulingTerm
当关联的接收器队列至少具有一定数量的元素时,与 nvidia::gxf::MessageAvailableSchedulingTerm
关联的实体将被执行。接收器使用调度项的 receiver
参数指定。允许实体执行的最小消息数由 min_size
指定。此调度项的可选参数是 front_stage_max_size
,即前台最大消息计数。如果设置了此参数,则仅当队列中的消息数不超过此计数时,调度项才允许执行。它可用于不消耗队列中所有消息的代码let。
在下面显示的示例中,队列的最小大小配置为 4。这意味着实体在队列中至少有 4 条消息之前不会执行。
- type: nvidia::gxf::MessageAvailableSchedulingTerm
parameters:
receiver: tensors
min_size: 4
MultiMessageAvailableSchedulingTerm
当提供的输入接收器列表组合起来至少具有给定数量的消息时,与 nvidia::gxf::MultiMessageAvailableSchedulingTerm
关联的实体将被执行。receivers
参数用于指定输入通道/接收器列表。允许实体执行所需的最小消息数由 min_size
参数设置。
考虑下面显示的示例。当所有三个接收器的组合消息数至少为 min_size 时;即 5,关联的实体将被执行。
- name: input_1
type: nvidia::gxf::test::MockReceiver
parameters:
max_capacity: 10
- name: input_2
type: nvidia::gxf::test::MockReceiver
parameters:
max_capacity: 10
- name: input_3
type: nvidia::gxf::test::MockReceiver
parameters:
max_capacity: 10
- type: nvidia::gxf::MultiMessageAvailableSchedulingTerm
parameters:
receivers: [input_1, input_2, input_3]
min_size: 5
BooleanSchedulingTerm
当其内部状态设置为 tick 时,与 nvidia::gxf::BooleanSchedulingTerm
关联的实体将被执行。参数 enable_tick
用于控制实体执行。调度项还具有两个 API enable_tick()
和 disable_tick()
来切换其内部状态。可以通过调用这些 API 来控制实体执行。如果 enable_tick
设置为 false,则实体不会执行(调度条件设置为 NEVER
)。如果 enable_tick
设置为 true,则实体将执行(调度条件设置为 READY
)。实体可以通过维护调度项的句柄来切换其状态。
示例用法
- type: nvidia::gxf::BooleanSchedulingTerm
parameters:
enable_tick: true
AsynchronousSchedulingTerm
AsynchronousSchedulingTerm
主要与处理异步事件的实体关联,这些异步事件发生在调度器执行的常规执行之外。由于这些事件本质上是非周期性的,因此 AsynchronousSchedulingTerm
可防止调度器定期轮询实体的状态并降低 CPU 利用率。AsynchronousSchedulingTerm
可以根据它正在等待的异步事件处于 READY
、WAIT
、WAIT\_EVENT
或 NEVER
状态。
异步事件的状态使用 nvidia::gxf::AsynchronousEventState
描述,并使用 setEventState
API 更新。
AsynchronousEventState | 描述 |
---|---|
READY | 初始状态,第一个 tick 待处理 |
WAIT | 异步服务请求尚未发送,无事可做,只能等待 |
EVENT_WAITING | 已向异步服务发送请求,等待事件完成通知 |
EVENT_DONE | 已收到事件完成通知,实体已准备好被 tick |
EVENT_NEVER | 实体不想再次被 tick,执行结束 |
与此调度项关联的实体很可能有一个异步线程,该线程可以在 GXF 调度器执行的常规执行周期之外更新调度项的状态。当调度项处于 WAIT
状态时,调度器会定期轮询实体的状态。当调度项处于 EVENT\_WAITING
状态时,调度器将不再检查实体的状态,直到它们收到事件通知,该通知可以使用 GxfEntityEventNotify
API 触发。将调度项的状态设置为 EVENT\_DONE
会自动将此通知发送给调度器。实体可以使用 EVENT\_NEVER
状态来指示其执行周期的结束。
示例用法
- name: async_scheduling_term
type: nvidia::gxf::AsynchronousSchedulingTerm
DownsteamReceptiveSchedulingTerm
此调度项指定,如果给定发射器的接收器可以接受新消息,则应执行实体。
示例用法
- name: downstream_st
type: nvidia::gxf::DownstreamReceptiveSchedulingTerm
parameters:
transmitter: output
min_size: 1
TargetTimeSchedulingTerm
此调度项允许在用户指定的时间戳执行。时间戳在提供的时钟上指定。
示例用法
- name: target_st
type: nvidia::gxf::TargetTimeSchedulingTerm
parameters:
clock: clock/manual_clock
ExpiringMessageAvailableSchedulingTerm
此调度等待接收器中指定数量的消息。当队列中接收到的第一条消息即将过期或队列中有足够的消息时,实体将被执行。receiver
参数用于设置要监视的接收器。参数 max_batch_size
和 max_delay_ns
分别指示要批量处理的最大消息数以及从第一条消息开始等待到执行实体的最大延迟。
在下面显示的示例中,当队列中的消息数大于 max_batch_size
(即 5)时,或者当从第一条消息到当前时间的延迟大于 max_delay_ns
(即 10000000)时,关联的实体将被执行。
- name: target_st
type: nvidia::gxf::ExpiringMessageAvailableSchedulingTerm
parameters:
receiver: signal
max_batch_size: 5
max_delay_ns: 10000000
clock: misc/clock
AND 组合
一个实体可以与多个调度项关联,这些调度项定义其执行行为。调度项是 AND
组合的,以描述实体的当前状态。为了使实体被调度器执行,所有调度项都必须处于 READY
状态,相反,当任何一个调度项达到 NEVER
状态时,实体将从执行中取消调度。AND
组合期间各种状态的优先级顺序为 NEVER
、WAIT\_EVENT
、WAIT
、WAIT\_TIME
和 READY
。
示例用法
components:
- name: integers
type: nvidia::gxf::DoubleBufferTransmitter
- name: fibonacci
type: nvidia::gxf::DoubleBufferTransmitter
- type: nvidia::gxf::CountSchedulingTerm
parameters:
count: 100
- type: nvidia::gxf::DownstreamReceptiveSchedulingTerm
parameters:
transmitter: integers
min_size: 1
BTSchedulingTerm
BT(行为树)调度项用于调度行为树实体本身及其在行为树中的子实体(如果有)。
示例用法
name: root
components:
- name: root_controller
type: nvidia::gxf::EntityCountFailureRepeatController
parameters:
max_repeat_count: 0
- name: root_st
type: nvidia::gxf::BTSchedulingTerm
parameters:
is_root: true
- name: root_codelet
type: nvidia::gxf::SequenceBehavior
parameters:
children: [ child1/child1_st ]
s_term: root_st
controller: root_controller