€•ÄŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ)/translations/zh_CN/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/zh_TW/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/it_IT/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/ja_JP/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/ko_KR/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/pt_BR/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ)/translations/sp_SP/trace/timerlat-tracer”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒTimerlat tracer”h]”hŒTimerlat tracer”…””}”(hh¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhh·h²hh³ŒC/var/lib/git/docbuild/linux/Documentation/trace/timerlat-tracer.rst”h´KubhŒ paragraph”“”)”}”(hX¬The timerlat tracer aims to help the preemptive kernel developers to find sources of wakeup latencies of real-time threads. Like cyclictest, the tracer sets a periodic timer that wakes up a thread. The thread then computes a *wakeup latency* value as the difference between the *current time* and the *absolute time* that the timer was set to expire. The main goal of timerlat is tracing in such a way to help kernel developers.”h]”(hŒáThe timerlat tracer aims to help the preemptive kernel developers to find sources of wakeup latencies of real-time threads. Like cyclictest, the tracer sets a periodic timer that wakes up a thread. The thread then computes a ”…””}”(hhÍh²hh³Nh´NubhŒemphasis”“”)”}”(hŒ*wakeup latency*”h]”hŒwakeup latency”…””}”(hh×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒ% value as the difference between the ”…””}”(hhÍh²hh³Nh´NubhÖ)”}”(hŒ*current time*”h]”hŒ current time”…””}”(hhéh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒ and the ”…””}”(hhÍh²hh³Nh´NubhÖ)”}”(hŒ*absolute time*”h]”hŒ absolute time”…””}”(hhûh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒp that the timer was set to expire. The main goal of timerlat is tracing in such a way to help kernel developers.”…””}”(hhÍh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubh¶)”}”(hhh]”(h»)”}”(hŒUsage”h]”hŒUsage”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjh²hh³hÊh´K ubhÌ)”}”(hŒ~Write the ASCII text "timerlat" into the current_tracer file of the tracing system (generally mounted at /sys/kernel/tracing).”h]”hŒ‚Write the ASCII text “timerlat†into the current_tracer file of the tracing system (generally mounted at /sys/kernel/tracing).”…””}”(hj$h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjh²hubhÌ)”}”(hŒ For example::”h]”hŒ For example:”…””}”(hj2h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjh²hubhŒ literal_block”“”)”}”(hŒX[root@f32 ~]# cd /sys/kernel/tracing/ [root@f32 tracing]# echo timerlat > current_tracer”h]”hŒX[root@f32 ~]# cd /sys/kernel/tracing/ [root@f32 tracing]# echo timerlat > current_tracer”…””}”hjBsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1j@h³hÊh´Khjh²hubhÌ)”}”(hŒ>It is possible to follow the trace by reading the trace file::”h]”hŒ=It is possible to follow the trace by reading the trace file:”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjh²hubjA)”}”(hX%[root@f32 tracing]# cat trace # tracer: timerlat # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # || / # |||| ACTIVATION # TASK-PID CPU# |||| TIMESTAMP ID CONTEXT LATENCY # | | | |||| | | | | -0 [000] d.h1 54.029328: #1 context irq timer_latency 932 ns <...>-867 [000] .... 54.029339: #1 context thread timer_latency 11700 ns -0 [001] dNh1 54.029346: #1 context irq timer_latency 2833 ns <...>-868 [001] .... 54.029353: #1 context thread timer_latency 9820 ns -0 [000] d.h1 54.030328: #2 context irq timer_latency 769 ns <...>-867 [000] .... 54.030330: #2 context thread timer_latency 3070 ns -0 [001] d.h1 54.030344: #2 context irq timer_latency 935 ns <...>-868 [001] .... 54.030347: #2 context thread timer_latency 4351 ns”h]”hX%[root@f32 tracing]# cat trace # tracer: timerlat # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # || / # |||| ACTIVATION # TASK-PID CPU# |||| TIMESTAMP ID CONTEXT LATENCY # | | | |||| | | | | -0 [000] d.h1 54.029328: #1 context irq timer_latency 932 ns <...>-867 [000] .... 54.029339: #1 context thread timer_latency 11700 ns -0 [001] dNh1 54.029346: #1 context irq timer_latency 2833 ns <...>-868 [001] .... 54.029353: #1 context thread timer_latency 9820 ns -0 [000] d.h1 54.030328: #2 context irq timer_latency 769 ns <...>-867 [000] .... 54.030330: #2 context thread timer_latency 3070 ns -0 [001] d.h1 54.030344: #2 context irq timer_latency 935 ns <...>-868 [001] .... 54.030347: #2 context thread timer_latency 4351 ns”…””}”hj`sbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´Khjh²hubhÌ)”}”(hX€The tracer creates a per-cpu kernel thread with real-time priority SCHED_FIFO:95 that prints two lines at every activation. The first is the *timer latency* observed at the *hardirq* context before the activation of the thread. The second is the *timer latency* observed by the thread. The ACTIVATION ID field serves to relate the *irq* execution to its respective *thread* execution.”h]”(hŒThe tracer creates a per-cpu kernel thread with real-time priority SCHED_FIFO:95 that prints two lines at every activation. The first is the ”…””}”(hjnh²hh³Nh´NubhÖ)”}”(hŒ*timer latency*”h]”hŒ timer latency”…””}”(hjvh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjnubhŒ observed at the ”…””}”(hjnh²hh³Nh´NubhÖ)”}”(hŒ *hardirq*”h]”hŒhardirq”…””}”(hjˆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjnubhŒ@ context before the activation of the thread. The second is the ”…””}”(hjnh²hh³Nh´NubhÖ)”}”(hŒ*timer latency*”h]”hŒ timer latency”…””}”(hjšh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjnubhŒF observed by the thread. The ACTIVATION ID field serves to relate the ”…””}”(hjnh²hh³Nh´NubhÖ)”}”(hŒ*irq*”h]”hŒirq”…””}”(hj¬h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjnubhŒ execution to its respective ”…””}”(hjnh²hh³Nh´NubhÖ)”}”(hŒ*thread*”h]”hŒthread”…””}”(hj¾h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjnubhŒ execution.”…””}”(hjnh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K.hjh²hubhÌ)”}”(hXThe *irq*/*thread* splitting is important to clarify in which context the unexpected high value is coming from. The *irq* context can be delayed by hardware-related actions, such as SMIs, NMIs, IRQs, or by thread masking interrupts. Once the timer happens, the delay can also be influenced by blocking caused by threads. For example, by postponing the scheduler execution via preempt_disable(), scheduler execution, or masking interrupts. Threads can also be delayed by the interference from other threads and IRQs.”h]”(hŒThe ”…””}”(hjÖh²hh³Nh´NubhÖ)”}”(hŒ*irq*”h]”hŒirq”…””}”(hjÞh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjÖubhŒ/”…””}”(hjÖh²hh³Nh´NubhÖ)”}”(hŒ*thread*”h]”hŒthread”…””}”(hjðh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjÖubhŒb splitting is important to clarify in which context the unexpected high value is coming from. The ”…””}”(hjÖh²hh³Nh´NubhÖ)”}”(hŒ*irq*”h]”hŒirq”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjÖubhXŠ context can be delayed by hardware-related actions, such as SMIs, NMIs, IRQs, or by thread masking interrupts. Once the timer happens, the delay can also be influenced by blocking caused by threads. For example, by postponing the scheduler execution via preempt_disable(), scheduler execution, or masking interrupts. Threads can also be delayed by the interference from other threads and IRQs.”…””}”(hjÖh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K5hjh²hubeh}”(h]”Œusage”ah ]”h"]”Œusage”ah$]”h&]”uh1hµhh·h²hh³hÊh´K ubh¶)”}”(hhh]”(h»)”}”(hŒTracer options”h]”hŒTracer options”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj"h²hh³hÊh´K?ubhÌ)”}”(hŒ”The timerlat tracer is built on top of osnoise tracer. So its configuration is also done in the osnoise/ config directory. The timerlat configs are:”h]”hŒ”The timerlat tracer is built on top of osnoise tracer. So its configuration is also done in the osnoise/ config directory. The timerlat configs are:”…””}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KAhj"h²hubhŒ block_quote”“”)”}”(hX`- cpus: CPUs at which a timerlat thread will execute. - timerlat_period_us: the period of the timerlat thread. - stop_tracing_us: stop the system tracing if a timer latency at the *irq* context higher than the configured value happens. Writing 0 disables this option. - stop_tracing_total_us: stop the system tracing if a timer latency at the *thread* context is higher than the configured value happens. Writing 0 disables this option. - print_stack: save the stack of the IRQ occurrence. The stack is printed after the *thread context* event, or at the IRQ handler if *stop_tracing_us* is hit. ”h]”hŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒ3cpus: CPUs at which a timerlat thread will execute.”h]”hÌ)”}”(hjPh]”hŒ3cpus: CPUs at which a timerlat thread will execute.”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KEhjNubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjIubjM)”}”(hŒ6timerlat_period_us: the period of the timerlat thread.”h]”hÌ)”}”(hjgh]”hŒ6timerlat_period_us: the period of the timerlat thread.”…””}”(hjih²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KFhjeubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjIubjM)”}”(hŒšstop_tracing_us: stop the system tracing if a timer latency at the *irq* context higher than the configured value happens. Writing 0 disables this option.”h]”hÌ)”}”(hŒšstop_tracing_us: stop the system tracing if a timer latency at the *irq* context higher than the configured value happens. Writing 0 disables this option.”h]”(hŒCstop_tracing_us: stop the system tracing if a timer latency at the ”…””}”(hj€h²hh³Nh´NubhÖ)”}”(hŒ*irq*”h]”hŒirq”…””}”(hjˆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj€ubhŒR context higher than the configured value happens. Writing 0 disables this option.”…””}”(hj€h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KGhj|ubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjIubjM)”}”(hŒ¦stop_tracing_total_us: stop the system tracing if a timer latency at the *thread* context is higher than the configured value happens. Writing 0 disables this option.”h]”hÌ)”}”(hŒ¦stop_tracing_total_us: stop the system tracing if a timer latency at the *thread* context is higher than the configured value happens. Writing 0 disables this option.”h]”(hŒIstop_tracing_total_us: stop the system tracing if a timer latency at the ”…””}”(hjªh²hh³Nh´NubhÖ)”}”(hŒ*thread*”h]”hŒthread”…””}”(hj²h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjªubhŒU context is higher than the configured value happens. Writing 0 disables this option.”…””}”(hjªh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KJhj¦ubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjIubjM)”}”(hŒprint_stack: save the stack of the IRQ occurrence. The stack is printed after the *thread context* event, or at the IRQ handler if *stop_tracing_us* is hit. ”h]”hÌ)”}”(hŒœprint_stack: save the stack of the IRQ occurrence. The stack is printed after the *thread context* event, or at the IRQ handler if *stop_tracing_us* is hit.”h]”(hŒRprint_stack: save the stack of the IRQ occurrence. The stack is printed after the ”…””}”(hjÔh²hh³Nh´NubhÖ)”}”(hŒ*thread context*”h]”hŒthread context”…””}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjÔubhŒ! event, or at the IRQ handler if ”…””}”(hjÔh²hh³Nh´NubhÖ)”}”(hŒ*stop_tracing_us*”h]”hŒstop_tracing_us”…””}”(hjîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjÔubhŒ is hit.”…””}”(hjÔh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KMhjÐubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjIubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1jGh³hÊh´KEhjCubah}”(h]”h ]”h"]”h$]”h&]”uh1jAh³hÊh´KEhj"h²hubeh}”(h]”Œtracer-options”ah ]”h"]”Œtracer options”ah$]”h&]”uh1hµhh·h²hh³hÊh´K?ubh¶)”}”(hhh]”(h»)”}”(hŒtimerlat and osnoise”h]”hŒtimerlat and osnoise”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj"h²hh³hÊh´KRubhÌ)”}”(hŒOThe timerlat can also take advantage of the osnoise: traceevents. For example::”h]”hŒNThe timerlat can also take advantage of the osnoise: traceevents. For example:”…””}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KThj"h²hubjA)”}”(hXü [root@f32 ~]# cd /sys/kernel/tracing/ [root@f32 tracing]# echo timerlat > current_tracer [root@f32 tracing]# echo 1 > events/osnoise/enable [root@f32 tracing]# echo 25 > osnoise/stop_tracing_total_us [root@f32 tracing]# tail -10 trace cc1-87882 [005] d..h... 548.771078: #402268 context irq timer_latency 13585 ns cc1-87882 [005] dNLh1.. 548.771082: irq_noise: local_timer:236 start 548.771077442 duration 7597 ns cc1-87882 [005] dNLh2.. 548.771099: irq_noise: qxl:21 start 548.771085017 duration 7139 ns cc1-87882 [005] d...3.. 548.771102: thread_noise: cc1:87882 start 548.771078243 duration 9909 ns timerlat/5-1035 [005] ....... 548.771104: #402268 context thread timer_latency 39960 ns”h]”hXü [root@f32 ~]# cd /sys/kernel/tracing/ [root@f32 tracing]# echo timerlat > current_tracer [root@f32 tracing]# echo 1 > events/osnoise/enable [root@f32 tracing]# echo 25 > osnoise/stop_tracing_total_us [root@f32 tracing]# tail -10 trace cc1-87882 [005] d..h... 548.771078: #402268 context irq timer_latency 13585 ns cc1-87882 [005] dNLh1.. 548.771082: irq_noise: local_timer:236 start 548.771077442 duration 7597 ns cc1-87882 [005] dNLh2.. 548.771099: irq_noise: qxl:21 start 548.771085017 duration 7139 ns cc1-87882 [005] d...3.. 548.771102: thread_noise: cc1:87882 start 548.771078243 duration 9909 ns timerlat/5-1035 [005] ....... 548.771104: #402268 context thread timer_latency 39960 ns”…””}”hjAsbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´KWhj"h²hubhÌ)”}”(hX(In this case, the root cause of the timer latency does not point to a single cause but to multiple ones. Firstly, the timer IRQ was delayed for 13 us, which may point to a long IRQ disabled section (see IRQ stacktrace section). Then the timer interrupt that wakes up the timerlat thread took 7597 ns, and the qxl:21 device IRQ took 7139 ns. Finally, the cc1 thread noise took 9909 ns of time before the context switch. Such pieces of evidence are useful for the developer to use other tracing methods to figure out how to debug and optimize the system.”h]”hX(In this case, the root cause of the timer latency does not point to a single cause but to multiple ones. Firstly, the timer IRQ was delayed for 13 us, which may point to a long IRQ disabled section (see IRQ stacktrace section). Then the timer interrupt that wakes up the timerlat thread took 7597 ns, and the qxl:21 device IRQ took 7139 ns. Finally, the cc1 thread noise took 9909 ns of time before the context switch. Such pieces of evidence are useful for the developer to use other tracing methods to figure out how to debug and optimize the system.”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kbhj"h²hubhÌ)”}”(hXHIt is worth mentioning that the *duration* values reported by the osnoise: events are *net* values. For example, the thread_noise does not include the duration of the overhead caused by the IRQ execution (which indeed accounted for 12736 ns). But the values reported by the timerlat tracer (timerlat_latency) are *gross* values.”h]”(hŒ It is worth mentioning that the ”…””}”(hj]h²hh³Nh´NubhÖ)”}”(hŒ *duration*”h]”hŒduration”…””}”(hjeh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj]ubhŒ, values reported by the osnoise: events are ”…””}”(hj]h²hh³Nh´NubhÖ)”}”(hŒ*net*”h]”hŒnet”…””}”(hjwh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj]ubhŒÞ values. For example, the thread_noise does not include the duration of the overhead caused by the IRQ execution (which indeed accounted for 12736 ns). But the values reported by the timerlat tracer (timerlat_latency) are ”…””}”(hj]h²hh³Nh´NubhÖ)”}”(hŒ*gross*”h]”hŒgross”…””}”(hj‰h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj]ubhŒ values.”…””}”(hj]h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kkhj"h²hubhÌ)”}”(hŒÇThe art below illustrates a CPU timeline and how the timerlat tracer observes it at the top and the osnoise: events at the bottom. Each "-" in the timelines means circa 1 us, and the time moves ==>::”h]”hŒÊThe art below illustrates a CPU timeline and how the timerlat tracer observes it at the top and the osnoise: events at the bottom. Each “-†in the timelines means circa 1 us, and the time moves ==>:”…””}”(hj¡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Krhj"h²hubjA)”}”(hX× External timer irq thread clock latency latency event 13585 ns 39960 ns | ^ ^ v | | |-------------| | |-------------+-------------------------| ^ ^ ======================================================================== [tmr irq] [dev irq] [another thread...^ v..^ v.......][timerlat/ thread] <-- CPU timeline ========================================================================= |-------| |-------| |--^ v-------| | | | | | + thread_noise: 9909 ns | +-> irq_noise: 6139 ns +-> irq_noise: 7597 ns”h]”hX× External timer irq thread clock latency latency event 13585 ns 39960 ns | ^ ^ v | | |-------------| | |-------------+-------------------------| ^ ^ ======================================================================== [tmr irq] [dev irq] [another thread...^ v..^ v.......][timerlat/ thread] <-- CPU timeline ========================================================================= |-------| |-------| |--^ v-------| | | | | | + thread_noise: 9909 ns | +-> irq_noise: 6139 ns +-> irq_noise: 7597 ns”…””}”hj¯sbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´Kvhj"h²hubeh}”(h]”Œtimerlat-and-osnoise”ah ]”h"]”Œtimerlat and osnoise”ah$]”h&]”uh1hµhh·h²hh³hÊh´KRubh¶)”}”(hhh]”(h»)”}”(hŒIRQ stacktrace”h]”hŒIRQ stacktrace”…””}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjÅh²hh³hÊh´KŠubhÌ)”}”(hŒ°The osnoise/print_stack option is helpful for the cases in which a thread noise causes the major factor for the timer latency, because of preempt or irq disabled. For example::”h]”hŒ¯The osnoise/print_stack option is helpful for the cases in which a thread noise causes the major factor for the timer latency, because of preempt or irq disabled. For example:”…””}”(hjÖh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KŒhjÅh²hubjA)”}”(hX [root@f32 tracing]# echo 500 > osnoise/stop_tracing_total_us [root@f32 tracing]# echo 500 > osnoise/print_stack [root@f32 tracing]# echo timerlat > current_tracer [root@f32 tracing]# tail -21 per_cpu/cpu7/trace insmod-1026 [007] dN.h1.. 200.201948: irq_noise: local_timer:236 start 200.201939376 duration 7872 ns insmod-1026 [007] d..h1.. 200.202587: #29800 context irq timer_latency 1616 ns insmod-1026 [007] dN.h2.. 200.202598: irq_noise: local_timer:236 start 200.202586162 duration 11855 ns insmod-1026 [007] dN.h3.. 200.202947: irq_noise: local_timer:236 start 200.202939174 duration 7318 ns insmod-1026 [007] d...3.. 200.203444: thread_noise: insmod:1026 start 200.202586933 duration 838681 ns timerlat/7-1001 [007] ....... 200.203445: #29800 context thread timer_latency 859978 ns timerlat/7-1001 [007] ....1.. 200.203446: => timerlat_irq => __hrtimer_run_queues => hrtimer_interrupt => __sysvec_apic_timer_interrupt => asm_call_irq_on_stack => sysvec_apic_timer_interrupt => asm_sysvec_apic_timer_interrupt => delay_tsc => dummy_load_1ms_pd_init => do_one_initcall => do_init_module => __do_sys_finit_module => do_syscall_64 => entry_SYSCALL_64_after_hwframe”h]”hX [root@f32 tracing]# echo 500 > osnoise/stop_tracing_total_us [root@f32 tracing]# echo 500 > osnoise/print_stack [root@f32 tracing]# echo timerlat > current_tracer [root@f32 tracing]# tail -21 per_cpu/cpu7/trace insmod-1026 [007] dN.h1.. 200.201948: irq_noise: local_timer:236 start 200.201939376 duration 7872 ns insmod-1026 [007] d..h1.. 200.202587: #29800 context irq timer_latency 1616 ns insmod-1026 [007] dN.h2.. 200.202598: irq_noise: local_timer:236 start 200.202586162 duration 11855 ns insmod-1026 [007] dN.h3.. 200.202947: irq_noise: local_timer:236 start 200.202939174 duration 7318 ns insmod-1026 [007] d...3.. 200.203444: thread_noise: insmod:1026 start 200.202586933 duration 838681 ns timerlat/7-1001 [007] ....... 200.203445: #29800 context thread timer_latency 859978 ns timerlat/7-1001 [007] ....1.. 200.203446: => timerlat_irq => __hrtimer_run_queues => hrtimer_interrupt => __sysvec_apic_timer_interrupt => asm_call_irq_on_stack => sysvec_apic_timer_interrupt => asm_sysvec_apic_timer_interrupt => delay_tsc => dummy_load_1ms_pd_init => do_one_initcall => do_init_module => __do_sys_finit_module => do_syscall_64 => entry_SYSCALL_64_after_hwframe”…””}”hjäsbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´KhjÅh²hubhÌ)”}”(hXIn this case, it is possible to see that the thread added the highest contribution to the *timer latency* and the stack trace, saved during the timerlat IRQ handler, points to a function named dummy_load_1ms_pd_init, which had the following code (on purpose)::”h]”(hŒZIn this case, it is possible to see that the thread added the highest contribution to the ”…””}”(hjòh²hh³Nh´NubhÖ)”}”(hŒ*timer latency*”h]”hŒ timer latency”…””}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjòubhŒš and the stack trace, saved during the timerlat IRQ handler, points to a function named dummy_load_1ms_pd_init, which had the following code (on purpose):”…””}”(hjòh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KªhjÅh²hubjA)”}”(hŒstatic int __init dummy_load_1ms_pd_init(void) { preempt_disable(); mdelay(1); preempt_enable(); return 0; }”h]”hŒstatic int __init dummy_load_1ms_pd_init(void) { preempt_disable(); mdelay(1); preempt_enable(); return 0; }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´K¯hjÅh²hubeh}”(h]”Œirq-stacktrace”ah ]”h"]”Œirq stacktrace”ah$]”h&]”uh1hµhh·h²hh³hÊh´KŠubh¶)”}”(hhh]”(h»)”}”(hŒUser-space interface”h]”hŒUser-space interface”…””}”(hj+h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj(h²hh³hÊh´K¹ubhÌ)”}”(hŒÔTimerlat allows user-space threads to use timerlat infra-structure to measure scheduling latency. This interface is accessible via a per-CPU file descriptor inside $tracing_dir/osnoise/per_cpu/cpu$ID/timerlat_fd.”h]”hŒÔTimerlat allows user-space threads to use timerlat infra-structure to measure scheduling latency. This interface is accessible via a per-CPU file descriptor inside $tracing_dir/osnoise/per_cpu/cpu$ID/timerlat_fd.”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K»hj(h²hubhÌ)”}”(hŒThe thread opens the file associated with its single processor”h]”hÌ)”}”(hj£h]”hŒ>The thread opens the file associated with its single processor”…””}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÄhj¡ubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjYubjM)”}”(hŒ.Only one thread can access the file at a time ”h]”hÌ)”}”(hŒ-Only one thread can access the file at a time”h]”hŒ-Only one thread can access the file at a time”…””}”(hj¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÅhj¸ubah}”(h]”h ]”h"]”h$]”h&]”uh1jLhjYubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1jGh³hÊh´KÁhjUubah}”(h]”h ]”h"]”h$]”h&]”uh1jAh³hÊh´KÁhj(h²hubhÌ)”}”(hŒˆThe open() syscall will fail if any of these conditions are not met. After opening the file descriptor, the user space can read from it.”h]”hŒˆThe open() syscall will fail if any of these conditions are not met. After opening the file descriptor, the user space can read from it.”…””}”(hjÜh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÇhj(h²hubhÌ)”}”(hŒˆThe read() system call will run a timerlat code that will arm the timer in the future and wait for it as the regular kernel thread does.”h]”hŒˆThe read() system call will run a timerlat code that will arm the timer in the future and wait for it as the regular kernel thread does.”…””}”(hjêh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÊhj(h²hubhÌ)”}”(hŒÝWhen the timer IRQ fires, the timerlat IRQ will execute, report the IRQ latency and wake up the thread waiting in the read. The thread will be scheduled and report the thread latency via tracer - as for the kernel thread.”h]”hŒÝWhen the timer IRQ fires, the timerlat IRQ will execute, report the IRQ latency and wake up the thread waiting in the read. The thread will be scheduled and report the thread latency via tracer - as for the kernel thread.”…””}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÍhj(h²hubhÌ)”}”(hŒ­The difference from the in-kernel timerlat is that, instead of re-arming the timer, timerlat will return to the read() system call. At this point, the user can run any code.”h]”hŒ­The difference from the in-kernel timerlat is that, instead of re-arming the timer, timerlat will return to the read() system call. At this point, the user can run any code.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÒhj(h²hubhÌ)”}”(hŒðIf the application rereads the file timerlat file descriptor, the tracer will report the return from user-space latency, which is the total latency. If this is the end of the work, it can be interpreted as the response time for the request.”h]”hŒðIf the application rereads the file timerlat file descriptor, the tracer will report the return from user-space latency, which is the total latency. If this is the end of the work, it can be interpreted as the response time for the request.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÖhj(h²hubhÌ)”}”(hŒ~After reporting the total latency, timerlat will restart the cycle, arm a timer, and go to sleep for the following activation.”h]”hŒ~After reporting the total latency, timerlat will restart the cycle, arm a timer, and go to sleep for the following activation.”…””}”(hj"h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÛhj(h²hubhÌ)”}”(hŒ½If at any time one of the conditions is broken, e.g., the thread migrates while in user space, or the timerlat tracer is disabled, the SIG_KILL signal will be sent to the user-space thread.”h]”hŒ½If at any time one of the conditions is broken, e.g., the thread migrates while in user space, or the timerlat tracer is disabled, the SIG_KILL signal will be sent to the user-space thread.”…””}”(hj0h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÞhj(h²hubhÌ)”}”(hŒ:Here is an basic example of user-space code for timerlat::”h]”hŒ9Here is an basic example of user-space code for timerlat:”…””}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kâhj(h²hubjA)”}”(hX#int main(void) { char buffer[1024]; int timerlat_fd; int retval; long cpu = 0; /* place in CPU 0 */ cpu_set_t set; CPU_ZERO(&set); CPU_SET(cpu, &set); if (sched_setaffinity(gettid(), sizeof(set), &set) == -1) return 1; snprintf(buffer, sizeof(buffer), "/sys/kernel/tracing/osnoise/per_cpu/cpu%ld/timerlat_fd", cpu); timerlat_fd = open(buffer, O_RDONLY); if (timerlat_fd < 0) { printf("error opening %s: %s\n", buffer, strerror(errno)); exit(1); } for (;;) { retval = read(timerlat_fd, buffer, 1024); if (retval < 0) break; } close(timerlat_fd); exit(0); }”h]”hX#int main(void) { char buffer[1024]; int timerlat_fd; int retval; long cpu = 0; /* place in CPU 0 */ cpu_set_t set; CPU_ZERO(&set); CPU_SET(cpu, &set); if (sched_setaffinity(gettid(), sizeof(set), &set) == -1) return 1; snprintf(buffer, sizeof(buffer), "/sys/kernel/tracing/osnoise/per_cpu/cpu%ld/timerlat_fd", cpu); timerlat_fd = open(buffer, O_RDONLY); if (timerlat_fd < 0) { printf("error opening %s: %s\n", buffer, strerror(errno)); exit(1); } for (;;) { retval = read(timerlat_fd, buffer, 1024); if (retval < 0) break; } close(timerlat_fd); exit(0); }”…””}”hjLsbah}”(h]”h ]”h"]”h$]”h&]”jPjQuh1j@h³hÊh´Kähj(h²hubeh}”(h]”Œuser-space-interface”ah ]”h"]”Œuser-space interface”ah$]”h&]”uh1hµhh·h²hh³hÊh´K¹ubeh}”(h]”Œtimerlat-tracer”ah ]”h"]”Œtimerlat tracer”ah$]”h&]”uh1hµhhh²hh³hÊh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÊuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hºNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÊŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jgjdjjjjjÂj¿j%j"j_j\uŒ nametypes”}”(jg‰j‰j‰j‰j%‰j_‰uh}”(jdh·jjjj"j¿j"j"jÅj\j(uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.