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