Fix: handle missing vec and empty softirq list on exit
[deliverable/lttng-analyses.git] / lttnganalyses / core / irq.py
1 # The MIT License (MIT)
2 #
3 # Copyright (C) 2015 - Antoine Busque <abusque@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 # SOFTWARE.
22
23 from .analysis import Analysis
24
25
26 class IrqAnalysis(Analysis):
27 def __init__(self, state, conf):
28 notification_cbs = {
29 'irq_handler_entry': self._process_irq_handler_entry,
30 'irq_handler_exit': self._process_irq_handler_exit,
31 'softirq_exit': self._process_softirq_exit
32 }
33
34 super().__init__(state, conf)
35 self._state.register_notification_cbs(notification_cbs)
36
37 # Indexed by irq 'id' (irq or vec)
38 self.hard_irq_stats = {}
39 self.softirq_stats = {}
40 # Log of individual interrupts
41 self.irq_list = []
42
43 def reset(self):
44 self.irq_list = []
45 for id in self.hard_irq_stats:
46 self.hard_irq_stats[id].reset()
47 for id in self.softirq_stats:
48 self.softirq_stats[id].reset()
49
50 def _process_irq_handler_entry(self, **kwargs):
51 id = kwargs['id']
52 name = kwargs['irq_name']
53 if id not in self.hard_irq_stats:
54 self.hard_irq_stats[id] = HardIrqStats(name)
55 elif self.hard_irq_stats[id].name != name:
56 self.hard_irq_stats[id].name = name
57
58 def _process_irq_handler_exit(self, **kwargs):
59 irq = kwargs['hard_irq']
60
61 if not self._filter_cpu(irq.cpu_id):
62 return
63
64 if self._conf.min_duration is not None and \
65 irq.duration < self._conf.min_duration:
66 return
67 if self._conf.max_duration is not None and \
68 irq.duration > self._conf.max_duration:
69 return
70
71 self.irq_list.append(irq)
72 if irq.id not in self.hard_irq_stats:
73 self.hard_irq_stats[irq.id] = HardIrqStats()
74
75 self.hard_irq_stats[irq.id].update_stats(irq)
76
77 def _process_softirq_exit(self, **kwargs):
78 irq = kwargs['softirq']
79
80 if not self._filter_cpu(irq.cpu_id):
81 return
82
83 if self._conf.min_duration is not None and \
84 irq.duration < self._conf.min_duration:
85 return
86 if self._conf.max_duration is not None and \
87 irq.duration > self._conf.max_duration:
88 return
89
90 self.irq_list.append(irq)
91 if irq.id not in self.softirq_stats:
92 name = SoftIrqStats.names[irq.id]
93 self.softirq_stats[irq.id] = SoftIrqStats(name)
94
95 self.softirq_stats[irq.id].update_stats(irq)
96
97
98 class IrqStats():
99 def __init__(self, name):
100 self.name = name
101 self.min_duration = None
102 self.max_duration = None
103 self.total_duration = 0
104 self.irq_list = []
105
106 @property
107 def count(self):
108 return len(self.irq_list)
109
110 def update_stats(self, irq):
111 if self.min_duration is None or irq.duration < self.min_duration:
112 self.min_duration = irq.duration
113
114 if self.max_duration is None or irq.duration > self.max_duration:
115 self.max_duration = irq.duration
116
117 self.total_duration += irq.duration
118 self.irq_list.append(irq)
119
120 def reset(self):
121 self.min_duration = None
122 self.max_duration = None
123 self.total_duration = 0
124 self.irq_list = []
125
126
127 class HardIrqStats(IrqStats):
128 def __init__(self, name='unknown'):
129 super().__init__(name)
130
131
132 class SoftIrqStats(IrqStats):
133 # from include/linux/interrupt.h
134 names = {0: 'HI_SOFTIRQ',
135 1: 'TIMER_SOFTIRQ',
136 2: 'NET_TX_SOFTIRQ',
137 3: 'NET_RX_SOFTIRQ',
138 4: 'BLOCK_SOFTIRQ',
139 5: 'BLOCK_IOPOLL_SOFTIRQ',
140 6: 'TASKLET_SOFTIRQ',
141 7: 'SCHED_SOFTIRQ',
142 8: 'HRTIMER_SOFTIRQ',
143 9: 'RCU_SOFTIRQ'}
144
145 def __init__(self, name):
146 super().__init__(name)
147 self.min_raise_latency = None
148 self.max_raise_latency = None
149 self.total_raise_latency = 0
150 self.raise_count = 0
151
152 def update_stats(self, irq):
153 super().update_stats(irq)
154
155 if irq.raise_ts is None:
156 return
157
158 raise_latency = irq.begin_ts - irq.raise_ts
159 if self.min_raise_latency is None or \
160 raise_latency < self.min_raise_latency:
161 self.min_raise_latency = raise_latency
162
163 if self.max_raise_latency is None or \
164 raise_latency > self.max_raise_latency:
165 self.max_raise_latency = raise_latency
166
167 self.total_raise_latency += raise_latency
168 self.raise_count += 1
169
170 def reset(self):
171 super().reset()
172 self.min_raise_latency = None
173 self.max_raise_latency = None
174 self.total_raise_latency = 0
175 self.raise_count = 0
This page took 0.033862 seconds and 5 git commands to generate.