1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/ftrace.h> 3 #include <linux/tracepoint.h> 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/init.h> 7 #include <linux/rv.h> 8 #include <rv/instrumentation.h> 9 10 #define MODULE_NAME "nrp" 11 12 #include <trace/events/irq.h> 13 #include <trace/events/sched.h> 14 #include <rv_trace.h> 15 #include <monitors/sched/sched.h> 16 17 #define RV_MON_TYPE RV_MON_PER_TASK 18 #include "nrp.h" 19 #include <rv/da_monitor.h> 20 21 #ifdef CONFIG_X86_LOCAL_APIC 22 #include <asm/trace/irq_vectors.h> 23 24 static void handle_vector_irq_entry(void *data, int vector) 25 { 26 da_handle_event(current, irq_entry_nrp); 27 } 28 29 static void attach_vector_irq(void) 30 { 31 rv_attach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); 32 if (IS_ENABLED(CONFIG_IRQ_WORK)) 33 rv_attach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); 34 if (IS_ENABLED(CONFIG_SMP)) { 35 rv_attach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); 36 rv_attach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry); 37 rv_attach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry); 38 } 39 } 40 41 static void detach_vector_irq(void) 42 { 43 rv_detach_trace_probe("nrp", local_timer_entry, handle_vector_irq_entry); 44 if (IS_ENABLED(CONFIG_IRQ_WORK)) 45 rv_detach_trace_probe("nrp", irq_work_entry, handle_vector_irq_entry); 46 if (IS_ENABLED(CONFIG_SMP)) { 47 rv_detach_trace_probe("nrp", reschedule_entry, handle_vector_irq_entry); 48 rv_detach_trace_probe("nrp", call_function_entry, handle_vector_irq_entry); 49 rv_detach_trace_probe("nrp", call_function_single_entry, handle_vector_irq_entry); 50 } 51 } 52 53 #else 54 /* We assume irq_entry tracepoints are sufficient on other architectures */ 55 static void attach_vector_irq(void) { } 56 static void detach_vector_irq(void) { } 57 #endif 58 59 static void handle_irq_entry(void *data, int irq, struct irqaction *action) 60 { 61 da_handle_event(current, irq_entry_nrp); 62 } 63 64 static void handle_sched_need_resched(void *data, struct task_struct *tsk, 65 int cpu, int tif) 66 { 67 /* 68 * Although need_resched leads to both the rescheduling and preempt_irq 69 * states, it is safer to start the monitor always in preempt_irq, 70 * which may not mirror the system state but makes the monitor simpler, 71 */ 72 if (tif == TIF_NEED_RESCHED) 73 da_handle_start_event(tsk, sched_need_resched_nrp); 74 } 75 76 static void handle_schedule_entry(void *data, bool preempt) 77 { 78 if (preempt) 79 da_handle_event(current, schedule_entry_preempt_nrp); 80 else 81 da_handle_event(current, schedule_entry_nrp); 82 } 83 84 static int enable_nrp(void) 85 { 86 int retval; 87 88 retval = da_monitor_init(); 89 if (retval) 90 return retval; 91 92 rv_attach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); 93 rv_attach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched); 94 rv_attach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); 95 attach_vector_irq(); 96 97 return 0; 98 } 99 100 static void disable_nrp(void) 101 { 102 rv_this.enabled = 0; 103 104 rv_detach_trace_probe("nrp", irq_handler_entry, handle_irq_entry); 105 rv_detach_trace_probe("nrp", sched_set_need_resched_tp, handle_sched_need_resched); 106 rv_detach_trace_probe("nrp", sched_entry_tp, handle_schedule_entry); 107 detach_vector_irq(); 108 109 da_monitor_destroy(); 110 } 111 112 static struct rv_monitor rv_this = { 113 .name = "nrp", 114 .description = "need resched preempts.", 115 .enable = enable_nrp, 116 .disable = disable_nrp, 117 .reset = da_monitor_reset_all, 118 .enabled = 0, 119 }; 120 121 static int __init register_nrp(void) 122 { 123 return rv_register_monitor(&rv_this, &rv_sched); 124 } 125 126 static void __exit unregister_nrp(void) 127 { 128 rv_unregister_monitor(&rv_this); 129 } 130 131 module_init(register_nrp); 132 module_exit(unregister_nrp); 133 134 MODULE_LICENSE("GPL"); 135 MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 136 MODULE_DESCRIPTION("nrp: need resched preempts."); 137