~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/watchdog_perf.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /kernel/watchdog_perf.c (Version linux-6.11.5) and /kernel/watchdog_perf.c (Version linux-4.17.19)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 /*                                                
  3  * Detect hard lockups on a system using perf     
  4  *                                                
  5  * started by Don Zickus, Copyright (C) 2010 R    
  6  *                                                
  7  * Note: Most of this code is borrowed heavily    
  8  * detector, so thanks to Ingo for the initial    
  9  * Some chunks also taken from the old x86-spe    
 10  * to those contributors as well.                 
 11  */                                               
 12                                                   
 13 #define pr_fmt(fmt) "NMI watchdog: " fmt          
 14                                                   
 15 #include <linux/nmi.h>                            
 16 #include <linux/atomic.h>                         
 17 #include <linux/module.h>                         
 18 #include <linux/sched/debug.h>                    
 19                                                   
 20 #include <asm/irq_regs.h>                         
 21 #include <linux/perf_event.h>                     
 22                                                   
 23 static DEFINE_PER_CPU(struct perf_event *, wat    
 24 static DEFINE_PER_CPU(struct perf_event *, dea    
 25 static struct cpumask dead_events_mask;           
 26                                                   
 27 static atomic_t watchdog_cpus = ATOMIC_INIT(0)    
 28                                                   
 29 #ifdef CONFIG_HARDLOCKUP_CHECK_TIMESTAMP          
 30 static DEFINE_PER_CPU(ktime_t, last_timestamp)    
 31 static DEFINE_PER_CPU(unsigned int, nmi_rearme    
 32 static ktime_t watchdog_hrtimer_sample_thresho    
 33                                                   
 34 void watchdog_update_hrtimer_threshold(u64 per    
 35 {                                                 
 36         /*                                        
 37          * The hrtimer runs with a period of (    
 38          *                                        
 39          * So it runs effectively with 2.5 tim    
 40          * watchdog. That means the hrtimer sh    
 41          * the NMI watchdog expires. The NMI w    
 42          * unhalted CPU cycles, so if Turbo-Mo    
 43          * might run way faster than expected     
 44          * smaller period than the one deduced    
 45          * frequency. Depending on the Turbo-M    
 46          * enough to get the NMI period smalle    
 47          * period and trigger false positives.    
 48          *                                        
 49          * The sample threshold is used to che    
 50          * the minimum time between two NMI sa    
 51          * prevents false positives.              
 52          *                                        
 53          * Set this to 4/5 of the actual watch    
 54          * hrtimer is guaranteed to fire at le    
 55          * watchdog threshold.                    
 56          */                                       
 57         watchdog_hrtimer_sample_threshold = pe    
 58 }                                                 
 59                                                   
 60 static bool watchdog_check_timestamp(void)        
 61 {                                                 
 62         ktime_t delta, now = ktime_get_mono_fa    
 63                                                   
 64         delta = now - __this_cpu_read(last_tim    
 65         if (delta < watchdog_hrtimer_sample_th    
 66                 /*                                
 67                  * If ktime is jiffies based,     
 68                  * jiffies from being incremen    
 69                  * at a stale timestamp and ne    
 70                  */                               
 71                 if (__this_cpu_inc_return(nmi_    
 72                         return false;             
 73         }                                         
 74         __this_cpu_write(nmi_rearmed, 0);         
 75         __this_cpu_write(last_timestamp, now);    
 76         return true;                              
 77 }                                                 
 78                                                   
 79 static void watchdog_init_timestamp(void)         
 80 {                                                 
 81         __this_cpu_write(nmi_rearmed, 0);         
 82         __this_cpu_write(last_timestamp, ktime    
 83 }                                                 
 84 #else                                             
 85 static inline bool watchdog_check_timestamp(vo    
 86 static inline void watchdog_init_timestamp(voi    
 87 #endif                                            
 88                                                   
 89 static struct perf_event_attr wd_hw_attr = {      
 90         .type           = PERF_TYPE_HARDWARE,     
 91         .config         = PERF_COUNT_HW_CPU_CY    
 92         .size           = sizeof(struct perf_e    
 93         .pinned         = 1,                      
 94         .disabled       = 1,                      
 95 };                                                
 96                                                   
 97 static struct perf_event_attr fallback_wd_hw_a    
 98         .type           = PERF_TYPE_HARDWARE,     
 99         .config         = PERF_COUNT_HW_CPU_CY    
100         .size           = sizeof(struct perf_e    
101         .pinned         = 1,                      
102         .disabled       = 1,                      
103 };                                                
104                                                   
105 /* Callback function for perf event subsystem     
106 static void watchdog_overflow_callback(struct     
107                                        struct     
108                                        struct     
109 {                                                 
110         /* Ensure the watchdog never gets thro    
111         event->hw.interrupts = 0;                 
112                                                   
113         if (!watchdog_check_timestamp())          
114                 return;                           
115                                                   
116         watchdog_hardlockup_check(smp_processo    
117 }                                                 
118                                                   
119 static int hardlockup_detector_event_create(vo    
120 {                                                 
121         unsigned int cpu;                         
122         struct perf_event_attr *wd_attr;          
123         struct perf_event *evt;                   
124                                                   
125         /*                                        
126          * Preemption is not disabled because     
127          * Ensure CPU-locality by calling this    
128          */                                       
129         WARN_ON(!is_percpu_thread());             
130         cpu = raw_smp_processor_id();             
131         wd_attr = &wd_hw_attr;                    
132         wd_attr->sample_period = hw_nmi_get_sa    
133                                                   
134         /* Try to register using hardware perf    
135         evt = perf_event_create_kernel_counter    
136                                                   
137         if (IS_ERR(evt)) {                        
138                 wd_attr = &fallback_wd_hw_attr    
139                 wd_attr->sample_period = hw_nm    
140                 evt = perf_event_create_kernel    
141                                                   
142         }                                         
143                                                   
144         if (IS_ERR(evt)) {                        
145                 pr_debug("Perf event create on    
146                          PTR_ERR(evt));           
147                 return PTR_ERR(evt);              
148         }                                         
149         this_cpu_write(watchdog_ev, evt);         
150         return 0;                                 
151 }                                                 
152                                                   
153 /**                                               
154  * watchdog_hardlockup_enable - Enable the loc    
155  * @cpu: The CPU to enable hard lockup on.        
156  */                                               
157 void watchdog_hardlockup_enable(unsigned int c    
158 {                                                 
159         WARN_ON_ONCE(cpu != smp_processor_id()    
160                                                   
161         if (hardlockup_detector_event_create()    
162                 return;                           
163                                                   
164         /* use original value for check */        
165         if (!atomic_fetch_inc(&watchdog_cpus))    
166                 pr_info("Enabled. Permanently     
167                                                   
168         watchdog_init_timestamp();                
169         perf_event_enable(this_cpu_read(watchd    
170 }                                                 
171                                                   
172 /**                                               
173  * watchdog_hardlockup_disable - Disable the l    
174  * @cpu: The CPU to enable hard lockup on.        
175  */                                               
176 void watchdog_hardlockup_disable(unsigned int     
177 {                                                 
178         struct perf_event *event = this_cpu_re    
179                                                   
180         WARN_ON_ONCE(cpu != smp_processor_id()    
181                                                   
182         if (event) {                              
183                 perf_event_disable(event);        
184                 this_cpu_write(watchdog_ev, NU    
185                 this_cpu_write(dead_event, eve    
186                 cpumask_set_cpu(smp_processor_    
187                 atomic_dec(&watchdog_cpus);       
188         }                                         
189 }                                                 
190                                                   
191 /**                                               
192  * hardlockup_detector_perf_cleanup - Cleanup     
193  *                                                
194  * Called from lockup_detector_cleanup(). Seri    
195  */                                               
196 void hardlockup_detector_perf_cleanup(void)       
197 {                                                 
198         int cpu;                                  
199                                                   
200         for_each_cpu(cpu, &dead_events_mask) {    
201                 struct perf_event *event = per    
202                                                   
203                 /*                                
204                  * Required because for_each_c    
205                  * CPU0 as set on UP kernels.     
206                  */                               
207                 if (event)                        
208                         perf_event_release_ker    
209                 per_cpu(dead_event, cpu) = NUL    
210         }                                         
211         cpumask_clear(&dead_events_mask);         
212 }                                                 
213                                                   
214 /**                                               
215  * hardlockup_detector_perf_stop - Globally st    
216  *                                                
217  * Special interface for x86 to handle the per    
218  */                                               
219 void __init hardlockup_detector_perf_stop(void    
220 {                                                 
221         int cpu;                                  
222                                                   
223         lockdep_assert_cpus_held();               
224                                                   
225         for_each_online_cpu(cpu) {                
226                 struct perf_event *event = per    
227                                                   
228                 if (event)                        
229                         perf_event_disable(eve    
230         }                                         
231 }                                                 
232                                                   
233 /**                                               
234  * hardlockup_detector_perf_restart - Globally    
235  *                                                
236  * Special interface for x86 to handle the per    
237  */                                               
238 void __init hardlockup_detector_perf_restart(v    
239 {                                                 
240         int cpu;                                  
241                                                   
242         lockdep_assert_cpus_held();               
243                                                   
244         if (!(watchdog_enabled & WATCHDOG_HARD    
245                 return;                           
246                                                   
247         for_each_online_cpu(cpu) {                
248                 struct perf_event *event = per    
249                                                   
250                 if (event)                        
251                         perf_event_enable(even    
252         }                                         
253 }                                                 
254                                                   
255 bool __weak __init arch_perf_nmi_is_available(    
256 {                                                 
257         return true;                              
258 }                                                 
259                                                   
260 /**                                               
261  * watchdog_hardlockup_probe - Probe whether N    
262  */                                               
263 int __init watchdog_hardlockup_probe(void)        
264 {                                                 
265         int ret;                                  
266                                                   
267         if (!arch_perf_nmi_is_available())        
268                 return -ENODEV;                   
269                                                   
270         ret = hardlockup_detector_event_create    
271                                                   
272         if (ret) {                                
273                 pr_info("Perf NMI watchdog per    
274         } else {                                  
275                 perf_event_release_kernel(this    
276                 this_cpu_write(watchdog_ev, NU    
277         }                                         
278         return ret;                               
279 }                                                 
280                                                   
281 /**                                               
282  * hardlockup_config_perf_event - Overwrite co    
283  * @str: number which identifies the raw perf     
284  */                                               
285 void __init hardlockup_config_perf_event(const    
286 {                                                 
287         u64 config;                               
288         char buf[24];                             
289         char *comma = strchr(str, ',');           
290                                                   
291         if (!comma) {                             
292                 if (kstrtoull(str, 16, &config    
293                         return;                   
294         } else {                                  
295                 unsigned int len = comma - str    
296                                                   
297                 if (len >= sizeof(buf))           
298                         return;                   
299                                                   
300                 if (strscpy(buf, str, sizeof(b    
301                         return;                   
302                 buf[len] = 0;                     
303                 if (kstrtoull(buf, 16, &config    
304                         return;                   
305         }                                         
306                                                   
307         wd_hw_attr.type = PERF_TYPE_RAW;          
308         wd_hw_attr.config = config;               
309 }                                                 
310                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php