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 "stall" 11 12 #include <trace/events/sched.h> 13 #include <rv_trace.h> 14 15 #define RV_MON_TYPE RV_MON_PER_TASK 16 #define HA_TIMER_TYPE HA_TIMER_WHEEL 17 #include "stall.h" 18 #include <rv/ha_monitor.h> 19 20 static u64 threshold_jiffies = 1000; 21 module_param(threshold_jiffies, ullong, 0644); 22 23 static u64 ha_get_env(struct ha_monitor *ha_mon, enum envs_stall env, u64 time_ns) 24 { 25 if (env == clk_stall) 26 return ha_get_clk_jiffy(ha_mon, env); 27 return ENV_INVALID_VALUE; 28 } 29 30 static void ha_reset_env(struct ha_monitor *ha_mon, enum envs_stall env, u64 time_ns) 31 { 32 if (env == clk_stall) 33 ha_reset_clk_jiffy(ha_mon, env); 34 } 35 36 static inline bool ha_verify_invariants(struct ha_monitor *ha_mon, 37 enum states curr_state, enum events event, 38 enum states next_state, u64 time_ns) 39 { 40 if (curr_state == enqueued_stall) 41 return ha_check_invariant_jiffy(ha_mon, clk_stall, time_ns); 42 return true; 43 } 44 45 static inline bool ha_verify_guards(struct ha_monitor *ha_mon, 46 enum states curr_state, enum events event, 47 enum states next_state, u64 time_ns) 48 { 49 bool res = true; 50 51 if (curr_state == dequeued_stall && event == sched_wakeup_stall) 52 ha_reset_env(ha_mon, clk_stall, time_ns); 53 else if (curr_state == running_stall && event == sched_switch_preempt_stall) 54 ha_reset_env(ha_mon, clk_stall, time_ns); 55 return res; 56 } 57 58 static inline void ha_setup_invariants(struct ha_monitor *ha_mon, 59 enum states curr_state, enum events event, 60 enum states next_state, u64 time_ns) 61 { 62 if (next_state == curr_state) 63 return; 64 if (next_state == enqueued_stall) 65 ha_start_timer_jiffy(ha_mon, clk_stall, threshold_jiffies, time_ns); 66 else if (curr_state == enqueued_stall) 67 ha_cancel_timer(ha_mon); 68 } 69 70 static bool ha_verify_constraint(struct ha_monitor *ha_mon, 71 enum states curr_state, enum events event, 72 enum states next_state, u64 time_ns) 73 { 74 if (!ha_verify_invariants(ha_mon, curr_state, event, next_state, time_ns)) 75 return false; 76 77 if (!ha_verify_guards(ha_mon, curr_state, event, next_state, time_ns)) 78 return false; 79 80 ha_setup_invariants(ha_mon, curr_state, event, next_state, time_ns); 81 82 return true; 83 } 84 85 static void handle_sched_switch(void *data, bool preempt, 86 struct task_struct *prev, 87 struct task_struct *next, 88 unsigned int prev_state) 89 { 90 if (!preempt && prev_state != TASK_RUNNING) 91 da_handle_start_event(prev, sched_switch_wait_stall); 92 else 93 da_handle_event(prev, sched_switch_preempt_stall); 94 da_handle_event(next, sched_switch_in_stall); 95 } 96 97 static void handle_sched_wakeup(void *data, struct task_struct *p) 98 { 99 da_handle_event(p, sched_wakeup_stall); 100 } 101 102 static int enable_stall(void) 103 { 104 int retval; 105 106 retval = da_monitor_init(); 107 if (retval) 108 return retval; 109 110 rv_attach_trace_probe("stall", sched_switch, handle_sched_switch); 111 rv_attach_trace_probe("stall", sched_wakeup, handle_sched_wakeup); 112 113 return 0; 114 } 115 116 static void disable_stall(void) 117 { 118 rv_this.enabled = 0; 119 120 rv_detach_trace_probe("stall", sched_switch, handle_sched_switch); 121 rv_detach_trace_probe("stall", sched_wakeup, handle_sched_wakeup); 122 123 da_monitor_destroy(); 124 } 125 126 static struct rv_monitor rv_this = { 127 .name = "stall", 128 .description = "identify tasks stalled for longer than a threshold.", 129 .enable = enable_stall, 130 .disable = disable_stall, 131 .reset = da_monitor_reset_all, 132 .enabled = 0, 133 }; 134 135 static int __init register_stall(void) 136 { 137 return rv_register_monitor(&rv_this, NULL); 138 } 139 140 static void __exit unregister_stall(void) 141 { 142 rv_unregister_monitor(&rv_this); 143 } 144 145 module_init(register_stall); 146 module_exit(unregister_stall); 147 148 MODULE_LICENSE("GPL"); 149 MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>"); 150 MODULE_DESCRIPTION("stall: identify tasks stalled for longer than a threshold."); 151