RCU-7——RCU trace
基于msm-5.4
定义在 include/trace/events/rcu.h 中,需要使能 CONFIG_RCU_TRACE, 在 update.c 中生成trace函数文件。trace event有:
rcu_utilization
rcu_grace_period
rcu_future_grace_period,
rcu_grace_period_init,
rcu_exp_grace_period,
rcu_exp_funnel_lock,
rcu_nocb_wake,
rcu_preempt_task,
rcu_unlock_preempted_task,
rcu_quiescent_state_report,
rcu_fqs,
rcu_dyntick,
rcu_callback,
rcu_kfree_callback,
rcu_batch_start,
rcu_invoke_callback,
rcu_invoke_kfree_callback,
rcu_batch_end,
rcu_torture_read,
rcu_barrier,
一、各trace简介
1. rcu_utilization
用于利用率计算的开始/结束标记的跟踪点。按照惯例,该字符串采用以下格式:
“Start <activity>”——标记指定活动的开始,例如“上下文切换”。允许嵌套。
“End <activity>”——标记指定活动的结束。
“<activity>”中的“@”字符是注释字符:数据缩减脚本将忽略“@”及其行的其余部分。
kernel/rcu/tree_plugin.h 和 tree.c 中有大量调用。trace打印参数有:
"Start context switch"
"End context switch"
"Start boost kthread@init"
"Start boost kthread@rcu_wait"
"End boost kthread@rcu_wait"
"Start boost kthread@rcu_yield"
"End boost kthread@rcu_yield"
"End boost kthread@notreached"
"Start scheduler-tick"
"End scheduler-tick"
"Start RCU core"
"End RCU core"
"Start CPU kthread@rcu_wait"
"End CPU kthread@rcu_wait"
"Start CPU kthread@rcu_yield"
"End CPU kthread@rcu_yield"
打印内容:
TP_printk("%s", __entry->s)
调用路径:
update_process_times //timer.c rcu_sched_clock_irq //tree.c rcu_core //tree.c rcu_note_context_switch //tree_plugin.h rcu_boost_kthread //tree_plugin.h trace_rcu_utilization
2. rcu_grace_period
宽限期事件的跟踪点。采用一个字符串来标识 RCU 类型、宽限期编号以及一个字符串来标识与宽限期相关的事件,如下所示:
“AccReadyCB”:CPU 将新的回调加速至 RCU_NEXT_READY_TAIL。
“AccWaitCB”:CPU 将新的回调加速至 RCU_WAIT_TAIL。
“newreq”:请求新的宽限期。
“start”:启动宽限期。
“cpustart”:CPU 首次注意到宽限期的开始。
“cpuqs”:CPU 进入静止状态。
“cpuonl”:CPU 上线。
“cpuofl”:CPU 下线。
“cpuofl-bgp”:CPU 在阻塞宽限期期间下线。
“reqwait”:GP kthread 处于休眠状态,等待宽限期请求。
"reqwaitsig": GP kthread 被 reqwait 状态的信号唤醒。
"fqswait": GP kthread 等待强制进入静止状态的时间。
"fqsstart": GP kthread 开始强制进入静止状态。
"fqsend": GP kthread 强制进入静止状态完成。
"fqswaitsig": GP kthread 被 fqswait 状态的信号唤醒。
"end": 结束宽限期。
"cpuend": CPU 首次注意到宽限期结束。
打印内容:
P_printk("%s %lu %s", __entry->rcuname, __entry->gp_seq, __entry->gpevent)
调用路径:
rcu_accelerate_cbs_unlocked rcu_advance_cbs note_gp_changes rcu_gp_init __note_gp_changes rcu_gp_cleanup rcu_core __call_rcu_core rcu_accelerate_cbs //tree.c rcu_start_this_gp //tree.c rcu_accelerate_cbs //tree.c __note_gp_changes //tree.c rcu_gp_init //tree.c rcu_gp_fqs_loop //tree.c rcu_gp_cleanup //tree.c rcu_gp_kthread //tree.c rcutree_dying_cpu //tree.c rcutree_prepare_cpu //tree.c rcu_qs //tree_plugin.h trace_rcu_grace_period
3. rcu_future_grace_period
用于未来宽限期事件的跟踪点。调用者应从 rcu_node 结构体中提取数据,rcuname 除外(来自 rcu_state 结构体)以及 event(以下之一):
“Startleaf”:根据叶节点数据请求宽限期。
“Prestarted”:有人抢先请求
“Startedleaf”:叶节点标记为未来 GP。
“Startedleafroot”:从叶节点到根节点的所有节点都标记为未来 GP。
“Startedroot”:根据根节点数据请求 nocb 宽限期。
“NoGPkthread”:RCU 宽限期 kthread 尚未启动。
“StartWait”:开始等待请求的宽限期。
“EndWait”:完成等待。
“Cleanup”:在上一次 GP 之后清理 rcu_node 结构体。
“CleanupMore”:已清理,需要另一个 GP。
打印内容:
TP_printk("%s %lu %lu %u %d %d %s", __entry->rcuname, __entry->gp_seq, __entry->gp_seq_req, __entry->level, __entry->grplo, __entry->grphi, __entry->gpevent)
调用路径:
rcu_accelerate_cbs //tree.c rcu_start_this_gp rcu_gp_cleanup //tree.c rcu_future_gp_cleanup rcu_spawn_gp_kthread //tree.c 创建的名为 rcu_state.name 的线程 rcu_gp_kthread rcu_gp_cleanup trace_rcu_this_gp //tree.c trace_rcu_future_grace_period
4. rcu_grace_period_init
宽限期初始化事件的跟踪点。这些事件通过 RCU 类型、新的宽限期编号、rcu_node 结构层级、rcu_node 结构覆盖的起始和结束 CPU 以及将要等待的 CPU 掩码来区分。除 RCU 类型外,其他所有信息均从 rcu_node 结构中提取。
打印内容:
TP_printk("%s %lu %u %d %d %lx", __entry->rcuname, __entry->gp_seq, __entry->level, __entry->grplo, __entry->grphi, __entry->qsmask)
调用路径:
early_initcall(rcu_spawn_gp_kthread) //tree.c rcu_spawn_gp_kthread //tree.c kthread_create(rcu_gp_kthread, NULL, "%s", rcu_state.name) //创建这个内核线程 rcu_gp_kthread //tree.c 需要增加宽限期时唤醒这个线程 rcu_gp_init //tree.c trace_rcu_grace_period_init(rcu_state.name, rnp...)
5. rcu_exp_grace_period
加急宽限期事件的跟踪点。采用标识 RCU 类型、加急宽限期序列号以及标识宽限期相关事件的字符串,如下所示:
“snap”:已捕获加急宽限期序列号的快照。
“start”:已启动实际加急宽限期。
“reset”:已开始重置树。
“select”:已开始选择要等待的 CPU。
“selectofl”:已选定 CPU 部分离线。
“startwait”:已开始等待选定的 CPU。
“end”:已结束实际加急宽限期。
“endwake”:已唤醒搭载者。
“done”:已由其他人为我们完成了加急宽限期。
打印内容:
TP_printk("%s %lu %s", __entry->rcuname, __entry->gpseq, __entry->gpevent)
调用路径:
synchronize_rcu_expedited //tree_exp.h rcu_exp_gp_seq_snap //tree_exp.h exp_funnel_lock //tree_exp.h synchronize_rcu_expedited //tree_exp.h sync_exp_work_done //tree_exp.h synchronize_rcu_expedited exp_funnel_lock //tree_exp.h sync_rcu_exp_select_cpus sync_rcu_exp_select_node_cpus //tree_exp.h sync_rcu_exp_select_cpus //tree_exp.h wait_rcu_exp_gp //tree_exp.h synchronize_rcu_expedited //tree_exp.h rcu_exp_sel_wait_wake //tree_exp.h rcu_exp_wait_wake //tree_exp.h synchronize_sched_expedited_wait //tree_exp.h rcu_exp_wait_wake //tree_exp.h trace_rcu_exp_gp_seq_snap
6. rcu_exp_funnel_lock
用于加速宽限期漏斗锁定事件的跟踪点。采用一个标识 RCU 类型的字符串、一个标识 rcu_node 组合树级别的整数、另一对标识与当前 rcu_node 结构关联的最低和最高编号 CPU 的整数,以及一个标识宽限期相关事件的字符串,如下所示:
“nxtlvl”:前进到 rcu_node 漏斗的下一级
“wait”:等待其他人执行加速 GP
打印内容:
TP_printk("%s %d %d %d %s", __entry->rcuname, __entry->level, __entry->grplo, __entry->grphi, __entry->gpevent)
调用路径:
synchronize_rcu_expedited //tree_exp.h exp_funnel_lock //tree_exp.h trace_rcu_exp_funnel_lock
7. rcu_nocb_wake
RCU 无 CB CPU 回调切换的跟踪点。此事件旨在协助调试这些切换。
第一个参数是 RCU 类型名称,第二个参数是提取的卸载 CPU 数量。第三个也是最后一个参数是一个字符串,如下所示:
“WakeEmpty”:唤醒 rcuo kthread,将第一个 CB 清空列表。
“WakeEmptyIsDeferred”:稍后唤醒 rcuo kthread,将第一个 CB 清空列表。
“WakeOvf”:唤醒 rcuo kthread,CB 列表很大。
“WakeOvfIsDeferred”:稍后唤醒 rcuo kthread,CB 列表很大。
“WakeNot”:不唤醒 rcuo kthread。
“WakeNotPoll”:不唤醒 rcuo kthread,因为它正在轮询。
“DeferredWake”:执行“IsDeferred”唤醒。
"Poll": 开始 rcu_nocb_poll 的新轮询周期。
"Sleep": 休眠等待 !rcu_nocb_poll 的 GP。
"CBSleep": 休眠等待 !rcu_nocb_poll 的 CB。
"WokeEmpty": rcuo kthread 唤醒发现空列表。
"WokeNonEmpty": rcuo kthread 唤醒发现非空列表。
"WaitQueue": 入队操作部分完成,定时等待其完成。
"WokeQueue": 部分入队操作现已完成。
打印内容:
TP_printk("%s %d %s", __entry->rcuname, __entry->cpu, __entry->reason)
调用路径:
wake_nocb_gp
wake_nocb_gp_defer
rcu_nocb_try_bypass
__call_rcu_nocb_wake
do_nocb_bypass_wakeup_timer
nocb_gp_wait
nocb_cb_wait
do_nocb_deferred_wakeup_common
trace_rcu_nocb_wake
8. rcu_preempt_task
可抢占式 RCU 读端临界区内阻塞任务的跟踪点。跟踪 RCU 的类型(将来可能包含 SRCU)、任务阻塞的宽限期编号(当前或下一个)以及任务的 PID。
打印内容:
TP_printk("%s %lu %d", __entry->rcuname, __entry->gp_seq, __entry->pid)
调用路径:
__schedule(preempt) //core.c rcu_virt_note_context_switch(false) //rcutree.h rcu_note_context_switch(preempt) //tree_plugin.h trace_rcu_preempt_task
9. rcu_unlock_preempted_task
跟踪在给定可抢占式 RCU 读端临界区内阻塞的任务,并确定其退出临界区的时间。跟踪 RCU 的类型(将来可能包含 SRCU)以及任务的 PID。
打印内容:
TP_printk("%s %lu %d", __entry->rcuname, __entry->gp_seq, __entry->pid)
调用路径:
rcu_exp_handler //tree_exp.h rcu_note_context_switch //tree_plugin.h rcu_flavor_sched_clock_irq //tree_plugin.h exit_rcu //tree_plugin.h rcu_preempt_deferred_qs rcu_read_unlock_special rcu_preempt_deferred_qs_irqrestore //tree_plugin.h rcu_gp_init //tree.c rcu_preempt_check_blocked_tasks trace_rcu_unlock_preempted_task
10. rcu_quiescent_state_report
用于报告静止状态事件的跟踪点。这些跟踪点通过 RCU 类型、宽限期编号、静止低级实体的掩码、rcu_node 结构级别、rcu_node 结构覆盖的起始和结束 CPU,以及是否有任何阻塞任务阻塞当前宽限期来区分。除 RCU 类型外,其他所有信息均从 rcu_node 结构中提取。
打印内容:
TP_printk("%s %lu %d", __entry->rcuname, __entry->gp_seq, __entry->pid)
调用路径:
rcu_gp_init //tree.c rcu_report_unblock_qs_rnp //tree.c rcu_report_qs_rdp //tree.c force_qs_rnp //tree.c rcu_cpu_starting //tree.c rcu_report_dead //tree.c rcu_report_qs_rnp //tree.c rcu_preempt_deferred_qs_irqrestore //tree_plugin.h trace_rcu_quiescent_state_report
11. rcu_fqs
force_quiescent_state() 检测到的静止状态的跟踪点。这些跟踪事件包括 RCU 的类型、被 CPU 阻止的宽限期编号、CPU 本身以及静止状态的类型。静止状态可以是“dti”(表示 dyntick-idle 模式)或“kick”(表示踢出处于 dyntick-idle 模式时间过长的 CPU)。
打印内容:
TP_printk("%s %lu %d %s", __entry->rcuname, __entry->gp_seq, __entry->cpu, __entry->qsevent)
调用路径:
rcu_gp_kthread //tree.c 内核线程 rcu_gp_fqs_loop //tree.c rcu_gp_fqs dyntick_save_progress_counter //tree.c rcu_gp_fqs rcu_implicit_dynticks_qs //tree.c trace_rcu_fqs
12. rcu_dyntick
dyntick-idle 进入/退出事件的跟踪点。这些事件以字符串作为参数:“Start”表示进入 dyntick-idle 模式,“Startirq”表示从 irq/NMI 进入,“End”表示退出,“Endirq”表示退出 irq/NMI,“--=”表示事件进入空闲模式,“++=”表示事件离开空闲模式。
这些事件还接受一对数字,分别表示相关事件前后的嵌套深度,以及第三个参数是 ->dynticks 计数器。请注意,任务相关事件和中断相关事件使用两个独立的计数器,irq/NMI 的“++=”和“--=”事件会将计数器的值改变 2,否则会改变 1。
打印内容:
TP_printk("%s %lx %lx %#3x", __entry->polarity, __entry->oldnesting, __entry->newnesting, __entry->dynticks & 0xfff)
调用路径:
rcu_idle_enter //tree.c 传false rcu_user_enter //tree.c 传true rcu_eqs_enter //tree.c rcu_nmi_exit //tree.c rcu_irq_exit //tree.c rcu_nmi_exit_common //tree.c rcu_idle_exit //tree.c rcu_user_exit rcu_eqs_exit //tree.c rcu_nmi_enter //tree.c rcu_irq_enter //tree.c rcu_nmi_enter_common //tree.c trace_rcu_dyntick
13. rcu_callback
注册单个 RCU 回调函数的跟踪点。第一个参数是 RCU 的类型,第二个参数是指向 RCU 回调本身的指针,第三个元素是排队的惰性回调数量,第四个元素是排队的回调总数。
打印内容:
TP_printk("%s rhp=%p func=%ps %ld/%ld", __entry->rcuname, __entry->rhp, __entry->func, __entry->qlen_lazy, __entry->qlen)
调用路径:
call_rcu //tree.c kfree_call_rcu //tree.c __call_rcu //tree.c trace_rcu_callback
14. rcu_kfree_callback
用于注册特殊 kfree() 形式的单个 RCU 回调的跟踪点。第一个参数是 RCU 类型,第二个参数是指向 RCU 回调的指针,第三个参数是回调在封闭的 RCU 保护数据结构中的偏移量,第四个参数是排队的惰性回调数量,第五个参数是排队的回调总数。
打印内容:
TP_printk("%s rhp=%p func=%ld %ld/%ld", __entry->rcuname, __entry->rhp, __entry->offset, __entry->qlen_lazy, __entry->qlen)
调用路径: 没有调用路径
15. rcu_batch_start
用于标记 rcu_do_batch 开始的跟踪点,用于启动 RCU 回调调用。第一个参数是 RCU 类型,第二个参数是排队的惰性回调数量,第三个参数是排队的回调总数,第四个参数是当前 RCU 回调批次限制。
打印内容:
TP_printk("%s CBs=%ld/%ld bl=%ld", __entry->rcuname, __entry->qlen_lazy, __entry->qlen, __entry->blimit)
调用路径:
rcu_init //tree.c open_softirq(RCU_SOFTIRQ, rcu_core_si) rcu_core_si rcu_spawn_core_kthreads //tree.c smp_hotplug_thread rcu_cpu_thread_spec //是每cpu一个的 rcuc/X 线程 rcu_cpu_kthread rcu_core rcu_do_batch //tree.c trace_rcu_batch_start
16. rcu_invoke_callback
单个 RCU 回调函数调用的跟踪点。第一个参数是 RCU 的类型,第二个参数是指向 RCU 回调函数本身的指针。
打印内容:
TP_printk("%s rhp=%p func=%ps", __entry->rcuname, __entry->rhp, __entry->func)
调用路径:
rcu_do_batch //tree.c __rcu_reclaim //rcu.h trace_rcu_invoke_callback
17. rcu_invoke_kfree_callback
用于调用特殊 kfree() 形式的单个 RCU 回调的跟踪点。第一个参数表示 RCU 类型,第二个参数是指向 RCU 回调的指针,第三个参数是回调在封闭的受 RCU 保护的数据结构中的偏移量。
打印内容:
TP_printk("%s rhp=%p func=%ld", __entry->rcuname, __entry->rhp, __entry->offset)
调用路径:
rcu_do_batch //tree.c __rcu_reclaim trace_rcu_invoke_kfree_callback
18. rcu_batch_end
在调用 RCU 回调后退出 rcu_do_batch 的跟踪点。第一个参数是 RCU 类型名称,第二个参数是实际调用的回调数量,第三个参数 (cb) 表示此批次开始时已准备好调用的回调是否仍在排队中,第四个参数 (nr) 是 need_resched() 的返回值,第五个参数 (iit) 表示当前任务为空闲任务,则为 1,第六个参数 (risk) 是 rcu_is_callbacks_kthread() 的返回值。
打印内容:
TP_printk("%s CBs-invoked=%d idle=%c%c%c%c", __entry->rcuname, __entry->callbacks_invoked,
__entry->cb ? 'C' : '.',
__entry->nr ? 'S' : '.',
__entry->iit ? 'I' : '.',
__entry->risk ? 'R' : '.')
调用路径:
rcu_do_batch //tree.c trace_rcu_batch_end
19. rcu_torture_read
rcutorture 读取器的跟踪点。第一个参数是从 rcutorture 的角度来看的 RCU 类型名称,第二个参数是回调地址。第三个参数是开始时间(以秒为单位),最后两个参数分别是读取开始和结束时的宽限期数字。注意,回调地址可以为 NULL。
打印内容:
TP_printk("%s torture read %p %luus c: %lu %lu",__entry->rcutorturename, __entry->rhp, __entry->secs, __entry->c_old, __entry->c)
调用路径:
rcu_ops.read_delay //rcutorture.c rcu_busted_ops.read_delay //rcutorture.c busted_srcud_ops.read_delay //rcutorture.c tasks_ops.read_delay //rcutorture.c trivial_ops.read_delay //rcutorture.c srcu_ops.read_delay //rcutorture.c srcud_ops.read_delay //rcutorture.c srcu_read_delay //rcutorture.c rcu_read_delay //rcutorture.c rcu_torture_one_read //rcutorture.c do_trace_rcu_torture_read //update.c trace_rcu_torture_read
20. rcu_barrier
rcu_barrier() 执行的跟踪点。字符串“s”描述了 rcu_barrier 的执行阶段:
“Begin”:rcu_barrier() 已启动。
“EarlyExit”:rcu_barrier() 被搭载,因此提前退出。
“Inc1”:rcu_barrier() 搭载检查计数器已递增。
“OfflineNoCB”:rcu_barrier() 在永不在线的 CPU 上发现回调函数。
“OnlineNoCB”:rcu_barrier() 发现在线且无 CB 的 CPU。
“OnlineQ”:rcu_barrier() 发现在线且有回调函数的 CPU。
“OnlineNQ”:rcu_barrier() 发现在线 CPU,但没有回调函数。
“IRQ”:rcu_barrier_callback() 回调函数已在远程 CPU 上发出。
“IRQNQ”:rcu_barrier_callback() 回调函数未发现回调函数。
“CB”:rcu_barrier_callback() 调用了一个回调,但不是最后一个。
“LastCB”:rcu_barrier_callback() 调用了最后一个回调。
“Inc2”:rcu_barrier() 捎带检查计数器已递增。
“cpu”参数表示 CPU,如果无意义则为 -1,“cnt”参数表示剩余回调的数量,“done”表示捎带计数。
打印内容:
TP_printk("%s %s cpu %d remaining %d # %lu", __entry->rcuname, __entry->s, __entry->cpu, __entry->cnt, __entry->done)
调用路径:
rcu_barrier_callback rcu_barrier_func rcu_barrier rcu_barrier_trace //tree.c trace_rcu_barrier
===> 看起来实现逻辑有点像有限状态机。
posted on 2025-05-23 17:09 Hello-World3 阅读(74) 评论(0) 收藏 举报