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