Commit | Line | Data |
---|---|---|
4ed24f86 JD |
1 | #!/usr/bin/env python3 |
2 | # | |
3 | # The MIT License (MIT) | |
4 | # | |
a3fa57c0 | 5 | # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com> |
4ed24f86 JD |
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 | ||
47ba125c JD |
25 | from linuxautomaton import sp, sv |
26 | ||
27 | ||
28 | class IrqStateProvider(sp.StateProvider): | |
29 | def __init__(self, state): | |
30 | self.state = state | |
31 | self.irq = state.interrupts | |
32 | self.cpus = state.cpus | |
33 | self.tids = state.tids | |
34 | self.irq["hard_count"] = 0 | |
35 | self.irq["soft_count"] = 0 | |
36 | self.irq["hard-per-cpu"] = {} | |
37 | self.irq["soft-per-cpu"] = {} | |
38 | self.irq["raise-per-cpu"] = {} | |
39 | self.irq["names"] = {} | |
40 | self.irq["hard-irqs"] = {} | |
41 | self.irq["soft-irqs"] = {} | |
42 | self.irq["raise-latency"] = {} | |
43 | self.irq["irq-list"] = [] | |
44 | cbs = { | |
45 | 'irq_handler_entry': self._process_irq_handler_entry, | |
46 | 'irq_handler_exit': self._process_irq_handler_exit, | |
47 | 'softirq_entry': self._process_softirq_entry, | |
48 | 'softirq_exit': self._process_softirq_exit, | |
49 | 'softirq_raise': self._process_softirq_raise, | |
50 | } | |
51 | self._register_cbs(cbs) | |
52 | ||
53 | def process_event(self, ev): | |
54 | self._process_event_cb(ev) | |
55 | ||
47ba125c JD |
56 | def entry(self, event, irqclass, idfield): |
57 | cpu_id = event["cpu_id"] | |
58 | i = sv.IRQ() | |
59 | i.irqclass = irqclass | |
60 | i.start_ts = event.timestamp | |
61 | i.cpu_id = cpu_id | |
62 | i.nr = event[idfield] | |
63 | return i | |
64 | ||
65 | def _process_irq_handler_entry(self, event): | |
66 | cpu_id = event["cpu_id"] | |
67 | self.irq["names"][event["irq"]] = event["name"] | |
68 | self.irq["hard_count"] += 1 | |
69 | i = self.entry(event, sv.IRQ.HARD_IRQ, "irq") | |
70 | self.irq["hard-per-cpu"][cpu_id] = i | |
71 | ||
72 | def _process_softirq_entry(self, event): | |
73 | cpu_id = event["cpu_id"] | |
74 | self.irq["soft_count"] += 1 | |
75 | i = self.entry(event, sv.IRQ.SOFT_IRQ, "vec") | |
76 | self.irq["soft-per-cpu"][cpu_id] = i | |
77 | if cpu_id in self.irq["raise-per-cpu"].keys() and \ | |
78 | self.irq["raise-per-cpu"][cpu_id] is not None and \ | |
79 | self.irq["raise-per-cpu"][cpu_id][1] == event["vec"]: | |
80 | i.raise_ts = self.irq["raise-per-cpu"][cpu_id][0] | |
81 | self.irq["raise-per-cpu"][cpu_id] = None | |
82 | ||
83 | def compute_stats(self, irq_entry, i): | |
84 | duration = i.stop_ts - i.start_ts | |
85 | if duration > irq_entry["max"]: | |
86 | irq_entry["max"] = duration | |
87 | if irq_entry["min"] == -1 or duration < irq_entry["min"]: | |
88 | irq_entry["min"] = duration | |
89 | irq_entry["count"] += 1 | |
90 | irq_entry["total"] += duration | |
91 | # compute raise latency if applicable | |
92 | if i.raise_ts == -1: | |
93 | return True | |
94 | latency = i.start_ts - i.raise_ts | |
95 | if latency > irq_entry["raise_max"]: | |
96 | irq_entry["raise_max"] = latency | |
97 | if irq_entry["raise_min"] == -1 or latency < irq_entry["raise_min"]: | |
98 | irq_entry["raise_min"] = latency | |
99 | irq_entry["raise_count"] += 1 | |
100 | irq_entry["raise_total"] += latency | |
101 | return True | |
102 | ||
103 | def exit(self, event, idfield, per_cpu_key, irq_type): | |
104 | cpu_id = event["cpu_id"] | |
105 | if cpu_id not in self.irq[per_cpu_key].keys() or \ | |
106 | self.irq[per_cpu_key][cpu_id] is None: | |
107 | return | |
108 | i = self.irq[per_cpu_key][cpu_id] | |
109 | if i.nr != event[idfield]: | |
110 | self.irq[per_cpu_key][cpu_id] = None | |
111 | return | |
112 | i.stop_ts = event.timestamp | |
113 | if not i.nr in self.irq[irq_type].keys(): | |
ca95b1c3 | 114 | self.irq[irq_type][i.nr] = sv.IRQ.init_irq_instance() |
47ba125c JD |
115 | |
116 | # filter out max/min | |
117 | duration = i.stop_ts - i.start_ts | |
f89605f0 JD |
118 | if hasattr(self.state, "max") and self.state.max is not None and \ |
119 | duration > self.state.max * 1000: | |
47ba125c | 120 | return False |
f89605f0 JD |
121 | if hasattr(self.state, "min") and self.state.min is not None and \ |
122 | duration < self.state.min * 1000: | |
47ba125c JD |
123 | return False |
124 | self.irq[irq_type][i.nr]["list"].append(i) | |
125 | self.compute_stats(self.irq[irq_type][i.nr], i) | |
126 | self.irq["irq-list"].append(i) | |
127 | return i | |
128 | ||
129 | def _process_irq_handler_exit(self, event): | |
130 | i = self.exit(event, "irq", "hard-per-cpu", "hard-irqs") | |
131 | if not i: | |
132 | return | |
133 | i.ret = event["ret"] | |
134 | ||
135 | def _process_softirq_exit(self, event): | |
136 | self.exit(event, "vec", "soft-per-cpu", "soft-irqs") | |
137 | ||
138 | def _process_softirq_raise(self, event): | |
139 | cpu_id = event["cpu_id"] | |
140 | self.irq["raise-per-cpu"][cpu_id] = ((event.timestamp, event["vec"])) |