Fix: correct typo in author email address
[deliverable/lttng-analyses.git] / linuxautomaton / linuxautomaton / block.py
1 #!/usr/bin/env python3
2 #
3 # The MIT License (MIT)
4 #
5 # Copyright (C) 2015 - Julien Desfossez <jdesfossez@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 linuxautomaton import sp, sv, common
26
27
28 class BlockStateProvider(sp.StateProvider):
29 def __init__(self, state):
30 self.state = state
31 self.cpus = state.cpus
32 self.disks = state.disks
33 self.tids = state.tids
34 self.remap_requests = []
35 cbs = {
36 'block_rq_complete': self._process_block_rq_complete,
37 'block_rq_issue': self._process_block_rq_issue,
38 'block_bio_remap': self._process_block_bio_remap,
39 'block_bio_backmerge': self._process_block_bio_backmerge,
40 }
41 self._register_cbs(cbs)
42
43 def process_event(self, ev):
44 self._process_event_cb(ev)
45
46 def _process_block_bio_remap(self, event):
47 dev = event["dev"]
48 sector = event["sector"]
49 old_dev = event["old_dev"]
50 old_sector = event["old_sector"]
51
52 for req in self.remap_requests:
53 if req["dev"] == old_dev and req["sector"] == old_sector:
54 req["dev"] = dev
55 req["sector"] = sector
56 return
57
58 req = {}
59 req["orig_dev"] = old_dev
60 req["dev"] = dev
61 req["sector"] = sector
62 self.remap_requests.append(req)
63
64 # For backmerge requests, just remove the request from the
65 # remap_requests queue, because we rely later on the nr_sector
66 # which has all the info we need.
67 def _process_block_bio_backmerge(self, event):
68 dev = event["dev"]
69 sector = event["sector"]
70 for req in self.remap_requests:
71 if req["dev"] == dev and req["sector"] == sector:
72 self.remap_requests.remove(req)
73
74 def _process_block_rq_issue(self, event):
75 dev = event["dev"]
76 sector = event["sector"]
77 nr_sector = event["nr_sector"]
78 # Note: since we don't know, we assume a sector is 512 bytes
79 block_size = 512
80 if nr_sector == 0:
81 return
82
83 rq = {}
84 rq["nr_sector"] = nr_sector
85 rq["rq_time"] = event.timestamp
86 rq["iorequest"] = sv.IORequest()
87 rq["iorequest"].iotype = sv.IORequest.IO_BLOCK
88 rq["iorequest"].begin = event.timestamp
89 rq["iorequest"].size = nr_sector * block_size
90
91 d = None
92 for req in self.remap_requests:
93 if req["dev"] == dev and req["sector"] == sector:
94 d = common.get_disk(req["orig_dev"], self.disks)
95 if not d:
96 d = common.get_disk(dev, self.disks)
97
98 d.nr_requests += 1
99 d.nr_sector += nr_sector
100 d.pending_requests[sector] = rq
101
102 if "tid" in event.keys():
103 tid = event["tid"]
104 if tid not in self.tids:
105 p = sv.Process()
106 p.tid = tid
107 self.tids[tid] = p
108 else:
109 p = self.tids[tid]
110 if p.pid != -1 and p.tid != p.pid:
111 p = self.tids[p.pid]
112 rq["pid"] = p
113 # even rwbs means read, odd means write
114 if event["rwbs"] % 2 == 0:
115 p.block_read += nr_sector * block_size
116 rq["iorequest"].operation = sv.IORequest.OP_READ
117 else:
118 p.block_write += nr_sector * block_size
119 rq["iorequest"].operation = sv.IORequest.OP_WRITE
120
121 def _process_block_rq_complete(self, event):
122 dev = event["dev"]
123 sector = event["sector"]
124 nr_sector = event["nr_sector"]
125 if nr_sector == 0:
126 return
127
128 d = None
129 for req in self.remap_requests:
130 if req["dev"] == dev and req["sector"] == sector:
131 d = common.get_disk(req["orig_dev"], self.disks)
132 self.remap_requests.remove(req)
133
134 if not d:
135 d = common.get_disk(dev, self.disks)
136
137 # ignore the completion of requests we didn't see the issue
138 # because it would mess up the latency totals
139 if sector not in d.pending_requests.keys():
140 return
141
142 rq = d.pending_requests[sector]
143 if rq["nr_sector"] != nr_sector:
144 return
145 d.completed_requests += 1
146 if rq["rq_time"] > event.timestamp:
147 print("Weird request TS", event.timestamp)
148 time_per_sector = (event.timestamp - rq["rq_time"]) / rq["nr_sector"]
149 d.request_time += time_per_sector
150 rq["iorequest"].duration = time_per_sector
151 rq["iorequest"].end = event.timestamp
152 d.rq_list.append(rq["iorequest"])
153 if "pid" in rq.keys():
154 rq["pid"].iorequests.append(rq["iorequest"])
155 del d.pending_requests[sector]
156
157 def dump_orphan_requests(self):
158 for req in self.remap_requests:
159 print("Orphan : %d : %d %d" % (req["orig_dev"], req["dev"],
160 req["sector"]))
This page took 0.040914 seconds and 5 git commands to generate.