专栏算法工具链FAQ Dataflow

FAQ Dataflow

DR_KAN2023-09-26
143
0

Q1: Send接口crash?

两种情况会导致这种问题产生:

  • 检查GetOutputPort中port id是否写错

  • 检查proc注册时是否与对应的port进行了关联


Q2: timer类型的proc并未按照设置的周期执行

如果发现周期时间实际执行时间波动比较大,一般是proc自身执行时长超过了timer的周期时间,导致调度器内部任务堆积。可自行检查回调函数是否执行时间过长。


Q3: proc未执行,如何定位?

可能因runtime.json中将对应的proc配置为disable,需要将disable字段配置为false(默认为false),若检查无误,可按照如下步骤进行定位:

修改日志等级为Debug并抓取日志

优先检查配置文件和程序内容,input等是否一致;检查pub和sub是否创建成功

关键日志

Pub端:

Sub端:

基于上述日志检查pub sub的协议 topic是否一致 如上述日志所描述,需要校验protocol,topic,domain_id是否一致。

检查配置的protocol是否支持跨进程通信 protocol默认为1表示INTRA方式,若需要跨进程,则需要修改protocol的值。每个sub或pub的protocol的值可查询日志:

检查module调用init接口或start接口是否均成功,防止在init或start时卡主,导致proc不执行。 关键日志:

检查Send接口是否成功发布依赖的消息 用户需要检查是否在回调中调用了Send接口。可参考日志: intra类型,需要设置communication.json里的comm_debug_enable为true:

非intra类型:

确认接收端是否收到消息:日志等级设成debug,查看日志有无关键字”sub receive msg, topic:”;若日志内无对应topic,说明接收端未接收到该消息,请检查输入/输出信息、communication通信相关设置等;

若上述条件均满足:

对MsgCondTriggerProc类型proc,可通过GetProcCondition("{proc_id}")->GetDesc()接口,打印查看condition条件是否符合预期,结合第六步日志,判断接收到的消息是否满足条件;
对MsgTimeStampSyncTriggerProc类型proc,查看是否有关键字got message and insert to slot in approximate time sync filter(确认filter是否接收到消息),erase enqueued message(收到消息但一直无法匹配上,超时被清出缓存);
对MsgTimerTriggerProc类型proc,查看是否有打印run timer user callback start, callback_id和run timer user callback end, callback_id。确认定时任务是否执行了。若有该日志出现但是proc仍未执行,则检查该类型proc的condition条件是否有设置,并检查条件是否满足。

检验条件如果失败,则会打印日志

可通过上述关键日志确认proc未执行原因。


Q4: proc未按照预期的expression执行,如何定位?

可按照如下步骤先行进行定位:

  1. 优先检查配置文件或代码Expression设置;

  2. Expression配置文件设置格式:port_id[require_num, ignore_sub]、代码内定义格式Require(port_index, require_num, ignore_sub),其中port_index与注册Proc时声明的input_port顺序一致,可通过Proc::GetResultIndex接口,获取port_id对应的port_index;
  3. 通过Proc::GetTriggerDesc接口,可获取expression表达式,确认是否与预期一致;

Q5: proc是否支持运行时更新expression?

  1. 支持,可以在Proc回调函数内,通过SetExpression接口更新expression,当下次框架检查触发逻辑时,即根据更新的expression判断触发条件;
  2. 不支持仅更新某个port的条件,proc的expression需要整体更新;


Q6: 启动后出现unknown proc/input/output setting字样,该如何处理?

出现这种报错,意味着配置文件中proc/port id和代码中的id对应不上,框架做了验证,需要用户进行配置文件的检查


Q7: 任务是常驻,如何退出?

可通过module的状态(status_)或者自定义状态的变更来退出常驻任务


Q8:如何保证任务异步执行安全?

有如下几种方法:

  1. 使用默认调度器,一个proc一个线程或者多个没有竞争关系的proc共用一个线程

  2. 使用保序型(ordered)的公平调度器

  3. 其它情况下需要用户在proc中对临界区进行保护


Q9:消息触发方式,Proc被调度前,框架内部逻辑是什么?

整体的时序关系:消息达到->判断Proc执行触发条件->绑定Proc与消息->生成任务->线程池中异步执行任务。


Q10:消息是否存在丢失? 消息是否存在堆积? 任务是否存在堆积?

  • 对Proc是否满足触发条件时,需要对消息进行缓存。存在场景dataflow框架主动丢弃消息:

  • synchronize_filter:等待时间超出阈值,丢弃该消息

  • sequence_filter:消息时间早于last_time或消息槽满,丢弃消息槽头部消息

  • condition_filter:消息槽满,丢弃消息槽头部消息 消息丢失时,会上报log给用户提示。

  • 设计不合理时,可能存在消息堆积现象:

  • 当消息到达的频率高于Proc执行频率,可能存在消息堆积现象。

  • 应用可以通过消息堆积诊断上报功能识别消息堆积现象。

  • 设计不合理时,任务可能存在堆积现象:

  • 如果proc数量过多或者单个proc执行的时间过长可能会发生任务堆积。

  • 应用可以通过profiling功能识别,堆积的任务调度延迟会增加


Q11:如何处理消息驱动以及单次延迟任务?

  • 消息驱动见上面消息触发

  • 目前dataflow中通过Reschedule或者timer可实现单次延迟任务


Q12:若任务执行时间比周期间隔长,调度行为是什么?若此时运行时修改周期间隔,调度行为是什么?

  • 对于trigger_type为default_trigger的timer的任务,proc严格按照周期产生任务,当任务执行时长大于周期时间时,会在线程池队列出现任务堆积,随着时间越长,则堆积数量累积。 此时修改周期间隔,已经累积的任务正常执行,触发超时的第一个时间点是调用更新接口的时间+更新的间隔,而后续剩余次数的任务将按照新的周期进行执行。

  • 对于trigger_type为self_trigger的timer的任务,不允许在线程池出现任务累积,而是在每次任务执行完成后自动再触发一次该任务,将该任务重新添加至线程池中。即对应timer的任务同时刻只能存在一个,要么处于线程池中,要么正在执行。对于这种类型的timer,不支持修改周期间隔,若修改则直接返回false。


Q13:如何保证周期任务不可重入的?是否支持通过多线程,并发执行?

目前对于同一个timer的多个任务,只支持串行执行。不支持并发。并保证该timer的任务都在一个线程上执行。


Q14:协程调度器支持哪些场景?

  • 支持普通任务的添加,每个proc的task将存储在同一队列。

  • 支持延迟任务,延迟任务存储在延迟队列的set中。

  • 支持常驻任务,为每个常驻任务分配一个协程。


Q15:协程调度器任务是否保证有序性?

协程调度器的任务具有有序性保证,每一个proc对应于一个协程,而每一个协程也会有一个队列来存储proc相关联的task。同时,每个协程在任务队列里存在task被执行时,其处于无法选定态,直至任务执行完成后,检查到该协程队列里还有任务,才可以重新执行下一个任务。


Q16:协程调度器线程安全性如何保证?

每个协程都具有独立的atomci_flag用于标记协程是否正在被调度,通过flag保证其他线程无法再获取该协程,从而保证该协程在多线程场景下的线程安全性。通过这种方式,避免了多个线程同时访问一个协程,导致程序崩溃的问题。


Q17:如何控制协程栈的切换?

协程具有resume和yield两个内部接口,resume用于控制切换至协程上次yield的地方,而yield用于在协程栈中将协程切出去至主栈,即保证了Processor执行线程可以继续从上次resume的地方接着执行。


Q18:Dag场景下,如何配置任务优先级?

在Dag场景下,推荐的方式是将Dag越往后的的节点优先级设的越高,以便调度器可以保证单帧延迟更低。


Q19:非pub/sub数据流场景如何处理?

Module接口中针对DAG的场景,对通信方式进行了精简,只支持publish/subscribe模式,若用户需要使用service、client等通信功能,可以通过Node接口进行处理(Module中包含一个node对象)。


Q20:创建module后的启动逻辑是什么?

启动步骤如下:

  1. 先调用Initialize接口,完成port、proc的创建(需要自定义InitPortsAndProcs接口)和初始化工作(需要自定义Init接口)

  2. 调用Start接口启动module,module中的port和proc开始工作

  3. 需要停止module的时候调用Stop接口,这用于想要主动控制module的状态(以用于后续某个时间再次启动module)

  4. 调用DeInitialize接口


Q21:一个module只能有一个proc吗?

一个module可以有多个proc,但如果多个proc之间存在module私有数据的竞争问题,需要用户自行处理,dataflow框架不能保证这样的多个proc在并发时数据是共享安全的。


Q22: new_allocator.h:120:4: error: no matching function for call to ‘hobot::dataflow::XXMsg::XXMsg()’

这种错误是由于XXMsg声明了有参构造函数,所以编译器不再自动提供无参构造函数导致的问题。解决这个问题只需要给XXMsg显示声明无参构造函数就行。


Q23: macro “DF_MODULE_INIT_RAW_OUTPUT_PORT” passed 3 arguments, but takes just 2

这个错误发生在通过宏注册port时,如果消息是模版类型,并且存在多个模板参数,那么模板多个模板参数之间的,导致了宏展开失败,可以通过using对模板类型取别名的方式解决(后期dataflow会对这个bug进行修复)

Q24: 通过mainboard2将进程拉起后,收不到trigger数据?

  1. check下process.json中auto_trigger字段是否被设置为了false,若配置文件中不设置此字段则默认为true

  2. 主线版本1.1.1-1.1.4存在bug 规避方案:用户程序编译添加宏DATAFLOW_INTRA_COMM


Q25: 日志出现can not open older shm version

communication对于shm文件未做到向前兼容。

解决方法:将/dev/shm/communication以及/dev/shm/communication_shm这两个文件删除


Q26: 日志出现open shm failed

发生此类错误是因为前一次communication非正常退出,导致shm文件损坏。

解决方法:将/dev/shm/communication_shm文件删除


Q27: mainboard2不能正常获取注册类

部分模块之前编译出的是.a静态库,没有直接生成.so动态库,而是将.a打包进了.so,导致classloader中的单例存在两个不同的对象

解决方法:直接将自定义module类生成.so,中间不要出现.a中转


Q28: Linux平台下Load library时报 undefined symbol

默认情况下,gcc在编译动态链接库时,不会报告未定义符号(undefined symbol)错误,只有在运行时才会发现此类错误.造成此种错误的原因是,class loader直接加载的动态库或者动态库依赖的其他动态库中使用了相应的符号但是此符号在所有的依赖库中都找不到,原因可能是某一个依赖库没有在搜索路径下面或者依赖的符号没有被编译到动态库中。

解决方法:通过nm或者grep找到未定义的符号是在哪个库中引入的,然后在此动态库中查找符号不存在的原因并解决。


Q29: module_desc_generator工具生成module desc文件时报:cannot open shared object file: No such file or directory

这个是由于动态库所在路径不在搜索路径下,加上export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib (将/path/to/lib改为动态库所有路径)即可解决

Q30: 如何获取任务的wcet时间?

任务编排工具仅根据任务属性做编排,实际使用时需要输入任务的wcet时间。确定性调度器的debug模式,可以为用户统计任务的wcet时间,但确定性调度器需要编排表作为输入,用户可以手动编排生成编排表,或利用编排工具生成编排表。

  • 将输入json内wcet均设为0,进入debug编排模式,生成debug编排表;

  • 将debug编排表作为确定性调度器的输入,启动确定性调度器debug模式,输出各个任务的wcet;


Q31: wcet_factor、wcet_gain作用?

wcet是统计值,实际场景中可能出现某次任务执行耗时超过wcet值,允许用户对wcet设置宽泛范围,实际编排时按照(wcet+wcet_gain)* wcet_factor,作为编排时任务的最大耗时。


Q32: DAG任务无外界消息依赖,如何获取period时间?

DAG输入节点无周期要求时,将输入json内DAG的period值设置为0,即可进入无period模式。


Q33: 是否支持将定时任务和DAG任务混合编排?

支持。将定时任务设置成只有单个节点的DAG,即可在dag编排模式下对周期任务和DAG任务混合编排。


Q34: dataflow_tool收不到数据?

可能下面这些因素导致:

  • 命令中topic、domain_id等输入不正确,如:配置参数中传入了topic,datatflow_tools使用默认topic

  • 未开启对应数据统计功能开关

  • 开启的功能(如profiling)与dataflow_tool中接收的(如 -u / –summary) 不是同一个功能

  • 如概要统计默认10s统计一次,如程序10s内退出则未收到数据


Q35: 日志报错 pub msg failed, convert base msg to derived msg failed, topic: xxx

在OutPort::Send接口中,检查消息类型与pub类型是否一致。


Q36: Expression规则说明

如不设置expression,则默认为每一个input_port均需要至少一条消息输入。

配置文件

expression 的规则为:inputport_id0[count, pass_if_no_sub] && inputport_id1[count, pass_if_no_sub] || inputport_id2[count, pass_if_no_sub]

count: 接受的消息数量,可以接收特殊值-1(即 ReqAll),表示把该消息槽中的所有消息都取走,设置 count 为-1的表达式恒为真。

pass_if_no_sub: 默认为1,代表该 input_port 为 nullptr 或 sub 被 disable 时该表达式也为true

&&: && 关联的两个条件表达式均满足时,该表达式整体才为真。

||: || 关联的两个表达式有一个满足时,该表达式整体就为真。|| 运算从左到右进行 check,若关联的左侧表达式为 true 则直接返回,不会进行右侧表达式的 check。

Expression表达式

某个port的消息在槽中的位置索引与注册INPUT_IDS参数参数的顺序相关,但建议proc的GetResultIndex接口获取,后期维护中INOUT_IDS的顺序变化时,代码兼容性更强。

Or 条件下消息堆积问题

当条件为input_port0[1] || input_port1[1]时,input_port0有消息时,永远只会拿到 or 左边的 input_port0 的消息,造成 input_port1 中消息堆积问题,可以尝试以下解决方案:

(input_port0[1] || input_port0[-1]) & (input_port0[1] || input_port0[-1])

场景:

  1. input_port0有消息而input_port1没有消息,满足条件,fetch消息(port0 1)

  2. input_port1有消息而input_port0没有消息,满足条件,fetch消息(port1 1)

  3. input_port0、input_port1均有消息,满足条件,fetch消息(port0 1,port1 1)

举例:

input_port0[2] && (input_port1[1] || input_port2[2, 0])

等同于:Require(0, 2)->And(Require(1, 1)->Or(Require(2, 2, 0)))

条件:

  1. port0必须有两条消息

  2. port1有一条消息和port2有两条消息 两个条件至少满足其中一个,若均满足,只会获取 || 左边的条件对应的消息。

场景:

  1. port0 两条消息,port1 一条消息,port2两条消息,满足条件,fetch消息(port0 2,port1 1)

  2. port0 两条消息,port2中sub为空,由于port2的第二个参数为0(pass_if_no_sub 为false),不满足条件

  3. port0 两条消息,port2 两条消息,满足条件,fetch消息(port0 2, port2 2)

  4. port0 一条消息,port1 一条消息,port2两条消息 不满足条件


Q37: 日志等级生效范围

在process.json中设置的日志等级全局生效,会覆盖所有的组件。


Q38: Reschedule与Timer proc

  • 当proc类型声明为为timer_proc时,proc本身就能够按照设置的间隔周期产生task进行执行。

  • Reschedule接口调用后,内部会产生新的task,在用户设置的时间执行。

如果用户想周期执行某一个任务,只需要选择其中一种方式即可,若timer_proc内部再次调用Reschedule接口后,会生成两个task。

Reschedule接口适合在condition_proc内调用,一次trigger触发这个proc后,内部就利用Reschedule形成周期任务。


算法工具链
官方教程
评论0
0/1000