// SPDX-License-Identifier: GPL-2.0/* * OS Noise Tracer: computes the OS Noise suffered by a running thread. * Timerlat Tracer: measures the wakeup latency of a timer triggered IRQ and thread. * * Based on "hwlat_detector" tracer by: * Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <jcm@redhat.com> * Copyright (C) 2013-2016 Steven Rostedt, Red Hat, Inc. <srostedt@redhat.com> * With feedback from Clark Williams <williams@redhat.com> * * And also based on the rtsl tracer presented on: * DE OLIVEIRA, Daniel Bristot, et al. Demystifying the real-time linux * scheduling latency. In: 32nd Euromicro Conference on Real-Time Systems * (ECRTS 2020). Schloss Dagstuhl-Leibniz-Zentrum fur Informatik, 2020. * * Copyright (C) 2021 Daniel Bristot de Oliveira, Red Hat, Inc. <bristot@redhat.com> */ #include <linux/kthread.h>#include <linux/tracefs.h>#include <linux/uaccess.h>#include <linux/cpumask.h>#include <linux/delay.h>#include <linux/sched/clock.h>#include <uapi/linux/sched/types.h>#include <linux/sched.h>#include <linux/string.h>#include "trace.h" #ifdef CONFIG_X86_LOCAL_APIC#include <asm/trace/irq_vectors.h>#undef TRACE_INCLUDE_PATH#undef TRACE_INCLUDE_FILE#endif /* CONFIG_X86_LOCAL_APIC */ #include <trace/events/irq.h>#include <trace/events/sched.h> #define CREATE_TRACE_POINTS#include <trace/events/osnoise.h> /* * Default values. */#define BANNER "osnoise: "#define DEFAULT_SAMPLE_PERIOD 1000000 /* 1s */#define DEFAULT_SAMPLE_RUNTIME 1000000 /* 1s */ #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */#define DEFAULT_TIMERLAT_PRIO 95 /* FIFO 95 */ /* * osnoise/options entries. */enum osnoise_options_index { OSN_DEFAULTS = 0, OSN_WORKLOAD, OSN_PANIC_ON_STOP, OSN_PREEMPT_DISABLE, OSN_IRQ_DISABLE, OSN_TIMERLAT_ALIGN, OSN_MAX}; static const char * const osnoise_options_str[OSN_MAX] = { "DEFAULTS", "OSNOISE_WORKLOAD", "PANIC_ON_STOP", "OSNOISE_PREEMPT_DISABLE", "OSNOISE_IRQ_DISABLE", "TIMERLAT_ALIGN" }; #define OSN_DEFAULT_OPTIONS 0x2static unsigned long osnoise_options = OSN_DEFAULT_OPTIONS; /* * trace_array of the enabled osnoise/timerlat instances. */struct osnoise_instance { struct list_head list; struct trace_array *tr;}; static struct list_head osnoise_instances; static void osnoise_print(const char *fmt, ...){ struct osnoise_instance *inst; struct trace_array *tr; va_list ap; rcu_read_lock(); list_for_each_entry_rcu(inst, &osnoise_instances, list) { tr = inst->tr; va_start(ap, fmt); trace_array_vprintk(tr, _RET_IP_, fmt, ap); va_end(ap); } rcu_read_unlock();} static bool osnoise_has_registered_instances(void){ return !!list_first_or_null_rcu(&osnoise_instances, struct osnoise_instance, list);} /* * osnoise_instance_registered - check if a tr is already registered */static int osnoise_instance_registered(struct trace_array *tr){ struct osnoise_instance *inst; int found = 0; rcu_read_lock(); list_for_each_entry_rcu(inst, &osnoise_instances, list) { if (inst->tr == tr) found = 1; } rcu_read_unlock(); return found;} /* * osnoise_register_instance - register a new trace instance * * Register a trace_array *tr in the list of instances running * osnoise/timerlat tracers. */static int osnoise_register_instance(struct trace_array *tr){ struct osnoise_instance *inst; /* * register/unregister serialization is provided by trace's * trace_types_lock. */ lockdep_assert_held(&trace_types_lock); trace_array_init_printk(tr); inst = kmalloc_obj(*inst); if (!inst) return -ENOMEM; INIT_LIST_HEAD_RCU(&inst->list); inst->tr = tr; list_add_tail_rcu(&inst->list, &osnoise_instances); return 0;} /* * osnoise_unregister_instance - unregister a registered trace instance * * Remove the trace_array *tr from the list of instances running * osnoise/timerlat tracers. */static void osnoise_unregister_instance(struct trace_array *tr){ struct osnoise_instance *inst; int found = 0; /* * register/unregister serialization is provided by trace's * trace_types_lock. */ list_for_each_entry_rcu(inst, &osnoise_instances, list, lockdep_is_held(&trace_types_lock)) { if (inst->tr == tr) { list_del_rcu(&inst->list); found = 1; break; } } if (!found) return; /* Do a full sync to ensure that tr remains valid, not just inst */ synchronize_rcu(); kvfree(inst);} /* * NMI runtime info. */struct osn_nmi { u64 count; u64 delta_start;}; /* * IRQ runtime info. */struct osn_irq { u64 count; u64 arrival_time; u64 delta_start;}; #define IRQ_CONTEXT 0#define THREAD_CONTEXT 1#define THREAD_URET 2/* * sofirq runtime info. */struct osn_softirq { u64 count; u64 arrival_time; u64 delta_start;}; /* * thread runtime info. */struct osn_thread { u64 count; u64 arrival_time; u64 delta_start;}; /* * Runtime information: this structure saves the runtime information used by * one sampling thread. */struct osnoise_variables { struct task_struct *kthread; bool sampling; pid_t pid; struct osn_nmi nmi; struct osn_irq irq; struct osn_softirq softirq; struct osn_thread thread; local_t int_counter;}; /* * Per-cpu runtime information. */static DEFINE_PER_CPU(struct osnoise_variables, per_cpu_osnoise_var); /* * this_cpu_osn_var - Return the per-cpu osnoise_variables on its relative CPU */static inline struct osnoise_variables *this_cpu_osn_var(void){ return this_cpu_ptr(&per_cpu_osnoise_var);} /* * Protect the interface. */static struct mutex interface_lock; #ifdef CONFIG_TIMERLAT_TRACER/* * Runtime information for the timer mode. */struct timerlat_variables { struct task_struct *kthread; struct hrtimer timer; u64 rel_period; u64 abs_period; bool tracing_thread; u64 count; bool uthread_migrate;}; static DEFINE_PER_CPU(struct timerlat_variables, per_cpu_timerlat_var); /* * timerlat wake-up offset for next thread with TIMERLAT_ALIGN set. */static atomic64_t align_next; /* * this_cpu_tmr_var - Return the per-cpu timerlat_variables on its relative CPU */static inline struct timerlat_variables *this_cpu_tmr_var(void){ return this_cpu_ptr(&per_cpu_timerlat_var);} /* * tlat_var_reset - Reset the values of the given timerlat_variables */static inline void tlat_var_reset(void){ struct timerlat_variables *tlat_var; int cpu; /* Synchronize with the timerlat interfaces */ mutex_lock(&interface_lock); /* * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ for_each_online_cpu(cpu) { tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu); if (tlat_var->kthread) hrtimer_cancel(&tlat_var->timer); memset(tlat_var, 0, sizeof(*tlat_var)); } /* * Reset also align_next, to be filled by a new offset by the first timerlat * thread that wakes up, if TIMERLAT_ALIGN is set. */ atomic64_set(&align_next, 0); mutex_unlock(&interface_lock);}#else /* CONFIG_TIMERLAT_TRACER */#define tlat_var_reset() do {} while (0)#endif /* CONFIG_TIMERLAT_TRACER */ /* * osn_var_reset - Reset the values of the given osnoise_variables */static inline void osn_var_reset(void){ struct osnoise_variables *osn_var; int cpu; /* * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ for_each_online_cpu(cpu) { osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu); memset(osn_var, 0, sizeof(*osn_var)); }} /* * osn_var_reset_all - Reset the value of all per-cpu osnoise_variables */static inline void osn_var_reset_all(void){ osn_var_reset(); tlat_var_reset();} /* * Tells NMIs to call back to the osnoise tracer to record timestamps. */bool trace_osnoise_callback_enabled; /* * Tracer data. */static struct osnoise_data { u64 sample_period; /* total sampling period */ u64 sample_runtime; /* active sampling portion of period */ u64 stop_tracing; /* stop trace in the internal operation (loop/irq) */ u64 stop_tracing_total; /* stop trace in the final operation (report/thread) */#ifdef CONFIG_TIMERLAT_TRACER u64 timerlat_period; /* timerlat period */ u64 timerlat_align_us; /* timerlat alignment */ u64 print_stack; /* print IRQ stack if total > */ int timerlat_tracer; /* timerlat tracer */#endif bool tainted; /* info users and developers about a problem */} osnoise_data = { .sample_period = DEFAULT_SAMPLE_PERIOD, .sample_runtime = DEFAULT_SAMPLE_RUNTIME, .stop_tracing = 0, .stop_tracing_total = 0,#ifdef CONFIG_TIMERLAT_TRACER .print_stack = 0, .timerlat_period = DEFAULT_TIMERLAT_PERIOD, .timerlat_align_us = 0, .timerlat_tracer = 0,#endif}; #ifdef CONFIG_TIMERLAT_TRACERstatic inline bool timerlat_enabled(void){ return osnoise_data.timerlat_tracer;} static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var){ struct timerlat_variables *tlat_var = this_cpu_tmr_var(); /* * If the timerlat is enabled, but the irq handler did * not run yet enabling timerlat_tracer, do not trace. */ if (!tlat_var->tracing_thread) { osn_var->softirq.arrival_time = 0; osn_var->softirq.delta_start = 0; return 0; } return 1;} static inline int timerlat_thread_exit(struct osnoise_variables *osn_var){ struct timerlat_variables *tlat_var = this_cpu_tmr_var(); /* * If the timerlat is enabled, but the irq handler did * not run yet enabling timerlat_tracer, do not trace. */ if (!tlat_var->tracing_thread) { osn_var->thread.delta_start = 0; osn_var->thread.arrival_time = 0; return 0; } return 1;}#else /* CONFIG_TIMERLAT_TRACER */static inline bool timerlat_enabled(void){ return false;} static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var){ return 1;}static inline int timerlat_thread_exit(struct osnoise_variables *osn_var){ return 1;}#endif #ifdef CONFIG_PREEMPT_RT/* * Print the osnoise header info. */static void print_osnoise_headers(struct seq_file *s){ if (osnoise_data.tainted) seq_puts(s, "# osnoise is tainted!\n"); seq_puts(s, "# _-------=> irqs-off\n"); seq_puts(s, "# / _------=> need-resched\n"); seq_puts(s, "# | / _-----=> need-resched-lazy\n"); seq_puts(s, "# || / _----=> hardirq/softirq\n"); seq_puts(s, "# ||| / _---=> preempt-depth\n"); seq_puts(s, "# |||| / _--=> preempt-lazy-depth\n"); seq_puts(s, "# ||||| / _-=> migrate-disable\n"); seq_puts(s, "# |||||| / "); seq_puts(s, " MAX\n"); seq_puts(s, "# ||||| / "); seq_puts(s, " SINGLE Interference counters:\n"); seq_puts(s, "# ||||||| RUNTIME "); seq_puts(s, " NOISE %% OF CPU NOISE +-----------------------------+\n"); seq_puts(s, "# TASK-PID CPU# ||||||| TIMESTAMP IN US "); seq_puts(s, " IN US AVAILABLE IN US HW NMI IRQ SIRQ THREAD\n"); seq_puts(s, "# | | | ||||||| | | "); seq_puts(s, " | | | | | | | |\n");}#else /* CONFIG_PREEMPT_RT */static void print_osnoise_headers(struct seq_file *s){ if (osnoise_data.tainted) seq_puts(s, "# osnoise is tainted!\n"); seq_puts(s, "# _-----=> irqs-off\n"); seq_puts(s, "# / _----=> need-resched\n"); seq_puts(s, "# | / _---=> hardirq/softirq\n"); seq_puts(s, "# || / _--=> preempt-depth\n"); seq_puts(s, "# ||| / _-=> migrate-disable "); seq_puts(s, " MAX\n"); seq_puts(s, "# |||| / delay "); seq_puts(s, " SINGLE Interference counters:\n"); seq_puts(s, "# ||||| RUNTIME "); seq_puts(s, " NOISE %% OF CPU NOISE +-----------------------------+\n"); seq_puts(s, "# TASK-PID CPU# ||||| TIMESTAMP IN US "); seq_puts(s, " IN US AVAILABLE IN US HW NMI IRQ SIRQ THREAD\n"); seq_puts(s, "# | | | ||||| | | "); seq_puts(s, " | | | | | | | |\n");}#endif /* CONFIG_PREEMPT_RT */ /* * osnoise_taint - report an osnoise error. */#define osnoise_taint(msg) ({ \ osnoise_print(msg); \ osnoise_data.tainted = true; \}) /* * Record an osnoise_sample into the tracer buffer. */static voidLines 1–500 of 3186. Load more
// SPDX-License-Identifier: GPL-2.0 /* * OS Noise Tracer: computes the OS Noise suffered by a running thread. * Timerlat Tracer: measures the wakeup latency of a timer triggered IRQ and thread. * * Based on "hwlat_detector" tracer by: * Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <jcm@redhat.com> * Copyright (C) 2013-2016 Steven Rostedt, Red Hat, Inc. <srostedt@redhat.com> * With feedback from Clark Williams <williams@redhat.com> * * And also based on the rtsl tracer presented on: * DE OLIVEIRA, Daniel Bristot, et al. Demystifying the real-time linux * scheduling latency. In: 32nd Euromicro Conference on Real-Time Systems * (ECRTS 2020). Schloss Dagstuhl-Leibniz-Zentrum fur Informatik, 2020. * * Copyright (C) 2021 Daniel Bristot de Oliveira, Red Hat, Inc. <bristot@redhat.com> */ #include <linux/kthread.h> #include <linux/tracefs.h> #include <linux/uaccess.h> #include <linux/cpumask.h> #include <linux/delay.h> #include <linux/sched/clock.h> #include <uapi/linux/sched/types.h> #include <linux/sched.h> #include <linux/string.h> #include "trace.h" #ifdef CONFIG_X86_LOCAL_APIC #include <asm/trace/irq_vectors.h> #undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_FILE #endif /* CONFIG_X86_LOCAL_APIC */ #include <trace/events/irq.h> #include <trace/events/sched.h> #define CREATE_TRACE_POINTS #include <trace/events/osnoise.h> /* * Default values. */ #define BANNER "osnoise: " #define DEFAULT_SAMPLE_PERIOD 1000000 /* 1s */ #define DEFAULT_SAMPLE_RUNTIME 1000000 /* 1s */ #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */ #define DEFAULT_TIMERLAT_PRIO 95 /* FIFO 95 */ /* * osnoise/options entries. */ enum osnoise_options_index { OSN_DEFAULTS = 0, OSN_WORKLOAD, OSN_PANIC_ON_STOP, OSN_PREEMPT_DISABLE, OSN_IRQ_DISABLE, OSN_TIMERLAT_ALIGN, OSN_MAX }; static const char * const osnoise_options_str[OSN_MAX] = { "DEFAULTS", "OSNOISE_WORKLOAD", "PANIC_ON_STOP", "OSNOISE_PREEMPT_DISABLE", "OSNOISE_IRQ_DISABLE", "TIMERLAT_ALIGN" }; #define OSN_DEFAULT_OPTIONS 0x2 static unsigned long osnoise_options = OSN_DEFAULT_OPTIONS; /* * trace_array of the enabled osnoise/timerlat instances. */ struct osnoise_instance { struct list_head list; struct trace_array *tr; }; static struct list_head osnoise_instances; static void osnoise_print(const char *fmt, ...) { struct osnoise_instance *inst; struct trace_array *tr; va_list ap; rcu_read_lock(); list_for_each_entry_rcu(inst, &osnoise_instances, list) { tr = inst->tr; va_start(ap, fmt); trace_array_vprintk(tr, _RET_IP_, fmt, ap); va_end(ap); } rcu_read_unlock(); } static bool osnoise_has_registered_instances(void) { return !!list_first_or_null_rcu(&osnoise_instances, struct osnoise_instance, list); } /* * osnoise_instance_registered - check if a tr is already registered */ static int osnoise_instance_registered(struct trace_array *tr) { struct osnoise_instance *inst; int found = 0; rcu_read_lock(); list_for_each_entry_rcu(inst, &osnoise_instances, list) { if (inst->tr == tr) found = 1; } rcu_read_unlock(); return found; } /* * osnoise_register_instance - register a new trace instance * * Register a trace_array *tr in the list of instances running * osnoise/timerlat tracers. */ static int osnoise_register_instance(struct trace_array *tr) { struct osnoise_instance *inst; /* * register/unregister serialization is provided by trace's * trace_types_lock. */ lockdep_assert_held(&trace_types_lock); trace_array_init_printk(tr); inst = kmalloc_obj(*inst); if (!inst) return -ENOMEM; INIT_LIST_HEAD_RCU(&inst->list); inst->tr = tr; list_add_tail_rcu(&inst->list, &osnoise_instances); return 0; } /* * osnoise_unregister_instance - unregister a registered trace instance * * Remove the trace_array *tr from the list of instances running * osnoise/timerlat tracers. */ static void osnoise_unregister_instance(struct trace_array *tr) { struct osnoise_instance *inst; int found = 0; /* * register/unregister serialization is provided by trace's * trace_types_lock. */ list_for_each_entry_rcu(inst, &osnoise_instances, list, lockdep_is_held(&trace_types_lock)) { if (inst->tr == tr) { list_del_rcu(&inst->list); found = 1; break; } } if (!found) return; /* Do a full sync to ensure that tr remains valid, not just inst */ synchronize_rcu(); kvfree(inst); } /* * NMI runtime info. */ struct osn_nmi { u64 count; u64 delta_start; }; /* * IRQ runtime info. */ struct osn_irq { u64 count; u64 arrival_time; u64 delta_start; }; #define IRQ_CONTEXT 0 #define THREAD_CONTEXT 1 #define THREAD_URET 2 /* * sofirq runtime info. */ struct osn_softirq { u64 count; u64 arrival_time; u64 delta_start; }; /* * thread runtime info. */ struct osn_thread { u64 count; u64 arrival_time; u64 delta_start; }; /* * Runtime information: this structure saves the runtime information used by * one sampling thread. */ struct osnoise_variables { struct task_struct *kthread; bool sampling; pid_t pid; struct osn_nmi nmi; struct osn_irq irq; struct osn_softirq softirq; struct osn_thread thread; local_t int_counter; }; /* * Per-cpu runtime information. */ static DEFINE_PER_CPU(struct osnoise_variables, per_cpu_osnoise_var); /* * this_cpu_osn_var - Return the per-cpu osnoise_variables on its relative CPU */ static inline struct osnoise_variables *this_cpu_osn_var(void) { return this_cpu_ptr(&per_cpu_osnoise_var); } /* * Protect the interface. */ static struct mutex interface_lock; #ifdef CONFIG_TIMERLAT_TRACER /* * Runtime information for the timer mode. */ struct timerlat_variables { struct task_struct *kthread; struct hrtimer timer; u64 rel_period; u64 abs_period; bool tracing_thread; u64 count; bool uthread_migrate; }; static DEFINE_PER_CPU(struct timerlat_variables, per_cpu_timerlat_var); /* * timerlat wake-up offset for next thread with TIMERLAT_ALIGN set. */ static atomic64_t align_next; /* * this_cpu_tmr_var - Return the per-cpu timerlat_variables on its relative CPU */ static inline struct timerlat_variables *this_cpu_tmr_var(void) { return this_cpu_ptr(&per_cpu_timerlat_var); } /* * tlat_var_reset - Reset the values of the given timerlat_variables */ static inline void tlat_var_reset(void) { struct timerlat_variables *tlat_var; int cpu; /* Synchronize with the timerlat interfaces */ mutex_lock(&interface_lock); /* * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ for_each_online_cpu(cpu) { tlat_var = per_cpu_ptr(&per_cpu_timerlat_var, cpu); if (tlat_var->kthread) hrtimer_cancel(&tlat_var->timer); memset(tlat_var, 0, sizeof(*tlat_var)); } /* * Reset also align_next, to be filled by a new offset by the first timerlat * thread that wakes up, if TIMERLAT_ALIGN is set. */ atomic64_set(&align_next, 0); mutex_unlock(&interface_lock); } #else /* CONFIG_TIMERLAT_TRACER */ #define tlat_var_reset() do {} while (0) #endif /* CONFIG_TIMERLAT_TRACER */ /* * osn_var_reset - Reset the values of the given osnoise_variables */ static inline void osn_var_reset(void) { struct osnoise_variables *osn_var; int cpu; /* * So far, all the values are initialized as 0, so * zeroing the structure is perfect. */ for_each_online_cpu(cpu) { osn_var = per_cpu_ptr(&per_cpu_osnoise_var, cpu); memset(osn_var, 0, sizeof(*osn_var)); } } /* * osn_var_reset_all - Reset the value of all per-cpu osnoise_variables */ static inline void osn_var_reset_all(void) { osn_var_reset(); tlat_var_reset(); } /* * Tells NMIs to call back to the osnoise tracer to record timestamps. */ bool trace_osnoise_callback_enabled; /* * Tracer data. */ static struct osnoise_data { u64 sample_period; /* total sampling period */ u64 sample_runtime; /* active sampling portion of period */ u64 stop_tracing; /* stop trace in the internal operation (loop/irq) */ u64 stop_tracing_total; /* stop trace in the final operation (report/thread) */ #ifdef CONFIG_TIMERLAT_TRACER u64 timerlat_period; /* timerlat period */ u64 timerlat_align_us; /* timerlat alignment */ u64 print_stack; /* print IRQ stack if total > */ int timerlat_tracer; /* timerlat tracer */ #endif bool tainted; /* info users and developers about a problem */ } osnoise_data = { .sample_period = DEFAULT_SAMPLE_PERIOD, .sample_runtime = DEFAULT_SAMPLE_RUNTIME, .stop_tracing = 0, .stop_tracing_total = 0, #ifdef CONFIG_TIMERLAT_TRACER .print_stack = 0, .timerlat_period = DEFAULT_TIMERLAT_PERIOD, .timerlat_align_us = 0, .timerlat_tracer = 0, #endif }; #ifdef CONFIG_TIMERLAT_TRACER static inline bool timerlat_enabled(void) { return osnoise_data.timerlat_tracer; } static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var) { struct timerlat_variables *tlat_var = this_cpu_tmr_var(); /* * If the timerlat is enabled, but the irq handler did * not run yet enabling timerlat_tracer, do not trace. */ if (!tlat_var->tracing_thread) { osn_var->softirq.arrival_time = 0; osn_var->softirq.delta_start = 0; return 0; } return 1; } static inline int timerlat_thread_exit(struct osnoise_variables *osn_var) { struct timerlat_variables *tlat_var = this_cpu_tmr_var(); /* * If the timerlat is enabled, but the irq handler did * not run yet enabling timerlat_tracer, do not trace. */ if (!tlat_var->tracing_thread) { osn_var->thread.delta_start = 0; osn_var->thread.arrival_time = 0; return 0; } return 1; } #else /* CONFIG_TIMERLAT_TRACER */ static inline bool timerlat_enabled(void) { return false; } static inline int timerlat_softirq_exit(struct osnoise_variables *osn_var) { return 1; } static inline int timerlat_thread_exit(struct osnoise_variables *osn_var) { return 1; } #endif #ifdef CONFIG_PREEMPT_RT /* * Print the osnoise header info. */ static void print_osnoise_headers(struct seq_file *s) { if (osnoise_data.tainted) seq_puts(s, "# osnoise is tainted!\n"); seq_puts(s, "# _-------=> irqs-off\n"); seq_puts(s, "# / _------=> need-resched\n"); seq_puts(s, "# | / _-----=> need-resched-lazy\n"); seq_puts(s, "# || / _----=> hardirq/softirq\n"); seq_puts(s, "# ||| / _---=> preempt-depth\n"); seq_puts(s, "# |||| / _--=> preempt-lazy-depth\n"); seq_puts(s, "# ||||| / _-=> migrate-disable\n"); seq_puts(s, "# |||||| / "); seq_puts(s, " MAX\n"); seq_puts(s, "# ||||| / "); seq_puts(s, " SINGLE Interference counters:\n"); seq_puts(s, "# ||||||| RUNTIME "); seq_puts(s, " NOISE %% OF CPU NOISE +-----------------------------+\n"); seq_puts(s, "# TASK-PID CPU# ||||||| TIMESTAMP IN US "); seq_puts(s, " IN US AVAILABLE IN US HW NMI IRQ SIRQ THREAD\n"); seq_puts(s, "# | | | ||||||| | | "); seq_puts(s, " | | | | | | | |\n"); } #else /* CONFIG_PREEMPT_RT */ static void print_osnoise_headers(struct seq_file *s) { if (osnoise_data.tainted) seq_puts(s, "# osnoise is tainted!\n"); seq_puts(s, "# _-----=> irqs-off\n"); seq_puts(s, "# / _----=> need-resched\n"); seq_puts(s, "# | / _---=> hardirq/softirq\n"); seq_puts(s, "# || / _--=> preempt-depth\n"); seq_puts(s, "# ||| / _-=> migrate-disable "); seq_puts(s, " MAX\n"); seq_puts(s, "# |||| / delay "); seq_puts(s, " SINGLE Interference counters:\n"); seq_puts(s, "# ||||| RUNTIME "); seq_puts(s, " NOISE %% OF CPU NOISE +-----------------------------+\n"); seq_puts(s, "# TASK-PID CPU# ||||| TIMESTAMP IN US "); seq_puts(s, " IN US AVAILABLE IN US HW NMI IRQ SIRQ THREAD\n"); seq_puts(s, "# | | | ||||| | | "); seq_puts(s, " | | | | | | | |\n"); } #endif /* CONFIG_PREEMPT_RT */ /* * osnoise_taint - report an osnoise error. */ #define osnoise_taint(msg) ({ \ osnoise_print(msg); \ osnoise_data.tainted = true; \ }) /* * Record an osnoise_sample into the tracer buffer. */ static void