Implement notification for communication from automaton to analyses
[deliverable/lttng-analyses.git] / linuxautomaton / linuxautomaton / sv.py
CommitLineData
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
bd3cd7c5 25import socket
44823c31 26from collections import OrderedDict
bd3cd7c5
JD
27
28
29class StateVariable:
30 pass
31
32
33class Process():
34 def __init__(self):
2b4a3c12
AB
35 self.tid = None
36 self.pid = None
bd3cd7c5
JD
37 self.comm = ""
38 # indexed by fd
39 self.fds = {}
40 # indexed by filename
41 self.closed_fds = {}
31d9c53b
AB
42 # filenames (indexed by timestamp) associated with given fd (top-level
43 # index) at a given point in time
44 self.chrono_fds = {}
bd3cd7c5
JD
45 self.current_syscall = {}
46 self.init_counts()
47
48 def init_counts(self):
49 self.cpu_ns = 0
50 self.migrate_count = 0
51 # network read/write
52 self.net_read = 0
53 self.net_write = 0
54 # disk read/write (might be cached)
55 self.disk_read = 0
56 self.disk_write = 0
57 # actual block access read/write
58 self.block_read = 0
59 self.block_write = 0
60 # unclassified read/write (FD passing and statedump)
61 self.unk_read = 0
62 self.unk_write = 0
63 # total I/O read/write
64 self.read = 0
65 self.write = 0
66 # last TS where the process was scheduled in
6ddb1dd6 67 self.last_sched = None
bd3cd7c5 68 # the process scheduled before this one
2b4a3c12 69 self.prev_tid = None
bd3cd7c5
JD
70 # indexed by syscall_name
71 self.syscalls = {}
72 self.perf = {}
73 self.dirty = 0
74 self.allocated_pages = 0
75 self.freed_pages = 0
76 self.total_syscalls = 0
77 # array of IORequest objects for freq analysis later (block and
78 # syscalls with no FD like sys_sync)
79 self.iorequests = []
80
44823c31
AB
81 def track_chrono_fd(self, fd, filename, fdtype, timestamp):
82 chrono_metadata = {}
83 chrono_metadata["filename"] = filename
84 chrono_metadata["fdtype"] = fdtype
85
86 if fd not in self.chrono_fds:
87 self.chrono_fds[fd] = OrderedDict()
88 self.chrono_fds[fd][timestamp] = chrono_metadata
89 else:
90 chrono_fd = self.chrono_fds[fd]
91 last_ts = next(reversed(chrono_fd))
92 if filename != chrono_fd[last_ts]["filename"]:
93 chrono_fd[timestamp] = chrono_metadata
94
bd3cd7c5
JD
95
96class CPU():
97 def __init__(self):
2b4a3c12 98 self.cpu_id = None
bd3cd7c5 99 self.cpu_ns = 0
2b4a3c12 100 self.current_tid = None
f4522f09
AB
101 self.current_hard_irq = None
102 self.current_soft_irq = None
bd3cd7c5
JD
103 self.start_task_ns = 0
104 self.perf = {}
105 self.wakeup_queue = []
106
107
994541c3
AB
108class MemoryManagement():
109 def __init__(self):
110 self.page_count = 0
111
112
bd3cd7c5 113class Syscall():
21167679 114 # One instance for each unique syscall name per process
bd3cd7c5
JD
115 def __init__(self):
116 self.name = ""
117 self.count = 0
21167679
JD
118 # duration min/max
119 self.min = None
120 self.max = 0
121 self.total_duration = 0
122 # list of all syscall events (SyscallEvent)
123 self.rq = []
124
125
126class SyscallEvent():
127 def __init__(self):
128 self.entry_ts = None
129 self.exit_ts = None
130 self.ret = None
131 self.duration = None
bd3cd7c5
JD
132
133
134class Disk():
135 def __init__(self):
136 self.name = ""
137 self.prettyname = ""
138 self.init_counts()
139
140 def init_counts(self):
141 self.nr_sector = 0
142 self.nr_requests = 0
143 self.completed_requests = 0
144 self.request_time = 0
145 self.pending_requests = {}
146 self.rq_list = []
147 self.max = None
148 self.min = None
149 self.total = None
150 self.count = None
151 self.rq_values = None
152 self.stdev = None
153
154
155class Iface():
156 def __init__(self):
157 self.name = ""
158 self.init_counts()
159
160 def init_counts(self):
161 self.recv_bytes = 0
162 self.recv_packets = 0
163 self.send_bytes = 0
164 self.send_packets = 0
165
166
167class FDType():
168 unknown = 0
169 disk = 1
170 net = 2
171 # not 100% sure they are network FDs (assumed when net_dev_xmit is
172 # called during a write syscall and the type in unknown).
173 maybe_net = 3
174
175
176class FD():
177 def __init__(self):
178 self.filename = ""
2b4a3c12 179 self.fd = None
bd3cd7c5
JD
180 # address family
181 self.family = socket.AF_UNSPEC
182 self.fdtype = FDType.unknown
183 # if FD was inherited, parent PID
2b4a3c12 184 self.parent = None
bd3cd7c5
JD
185 self.init_counts()
186
187 def init_counts(self):
188 # network read/write
189 self.net_read = 0
190 self.net_write = 0
191 # disk read/write (might be cached)
192 self.disk_read = 0
193 self.disk_write = 0
194 # unclassified read/write (FD passing and statedump)
195 self.unk_read = 0
196 self.unk_write = 0
197 # total read/write
198 self.read = 0
199 self.write = 0
200 self.open = 0
201 self.close = 0
202 self.cloexec = 0
203 # array of syscall IORequest objects for freq analysis later
204 self.iorequests = []
205
206
207class IRQ():
bd3cd7c5
JD
208 # from include/linux/interrupt.h
209 soft_names = {0: "HI_SOFTIRQ",
210 1: "TIMER_SOFTIRQ",
211 2: "NET_TX_SOFTIRQ",
212 3: "NET_RX_SOFTIRQ",
213 4: "BLOCK_SOFTIRQ",
214 5: "BLOCK_IOPOLL_SOFTIRQ",
215 6: "TASKLET_SOFTIRQ",
216 7: "SCHED_SOFTIRQ",
217 8: "HRTIMER_SOFTIRQ",
218 9: "RCU_SOFTIRQ"}
219
f4522f09
AB
220 def __init__(self, id, start_ts=None):
221 self.id = id
222 self.start_ts = start_ts
2b4a3c12 223 self.stop_ts = None
bd3cd7c5 224
f4522f09
AB
225
226class HardIRQ(IRQ):
227 def __init__(self, id, start_ts):
228 super().__init__(id, start_ts)
229 self.ret = None
230
231 @classmethod
232 def new_from_irq_handler_entry(cls, event):
233 id = event["irq"]
234 start_ts = event.timestamp
235 return cls(id, start_ts)
236
237
238class SoftIRQ(IRQ):
239 def __init__(self, id, raise_ts=None, start_ts=None):
240 super().__init__(id)
241 self.raise_ts = raise_ts
242
243 @classmethod
244 def new_from_softirq_raise(cls, event):
245 id = event["vec"]
246 raise_ts = event.timestamp
247 return cls(id, raise_ts)
248
249 @classmethod
250 def new_from_softirq_entry(cls, event):
251 id = event["vec"]
252 start_ts = event.timestamp
253 return cls(id, start_ts=start_ts)
ca95b1c3 254
bd3cd7c5
JD
255
256class IORequest():
257 # I/O "type"
258 IO_SYSCALL = 1
259 IO_BLOCK = 2
260 IO_NET = 3
261 # I/O operations
262 OP_OPEN = 1
263 OP_READ = 2
264 OP_WRITE = 3
265 OP_CLOSE = 4
266 OP_SYNC = 5
267
268 def __init__(self):
269 # IORequest.IO_*
270 self.iotype = None
271 # bytes for syscalls and net, sectors for block
272 # FIXME: syscalls handling vectors (vector size missing)
273 self.size = None
274 # for syscalls and block: delay between issue and completion
275 # of the request
276 self.duration = None
277 # IORequest.OP_*
278 self.operation = None
279 # syscall name
280 self.name = None
281 # begin syscall timestamp
282 self.begin = None
283 # end syscall timestamp
284 self.end = None
285 # current process
286 self.proc = None
287 # current FD (for syscalls)
288 self.fd = None
289 # buffers dirtied during the operation
290 self.dirty = 0
291 # pages allocated during the operation
292 self.page_alloc = 0
293 # pages freed during the operation
294 self.page_free = 0
295 # pages written on disk during the operation
296 self.page_written = 0
297 # kswapd was forced to wakeup during the operation
298 self.woke_kswapd = False
299 # estimated pages flushed during a sync operation
300 self.page_cleared = 0
301
302
303class Syscalls_stats():
304 def __init__(self):
305 self.read_max = 0
306 self.read_min = None
307 self.read_total = 0
308 self.read_count = 0
309 self.read_rq = []
310 self.all_read = []
311
312 self.write_max = 0
313 self.write_min = None
314 self.write_total = 0
315 self.write_count = 0
316 self.write_rq = []
317 self.all_write = []
318
319 self.open_max = 0
320 self.open_min = None
321 self.open_total = 0
322 self.open_count = 0
323 self.open_rq = []
324 self.all_open = []
325
326 self.sync_max = 0
327 self.sync_min = None
328 self.sync_total = 0
329 self.sync_count = 0
330 self.sync_rq = []
331 self.all_sync = []
332
333
334class SyscallConsts():
335 # TODO: decouple socket/family logic from this class
336 INET_FAMILIES = [socket.AF_INET, socket.AF_INET6]
337 DISK_FAMILIES = [socket.AF_UNIX]
338 # list nof syscalls that open a FD on disk (in the exit_syscall event)
339 DISK_OPEN_SYSCALLS = ["sys_open", "syscall_entry_open",
340 "sys_openat", "syscall_entry_openat"]
341 # list of syscalls that open a FD on the network
342 # (in the exit_syscall event)
343 NET_OPEN_SYSCALLS = ["sys_accept", "syscall_entry_accept",
af16b456 344 "sys_accept4", "syscall_entry_accept4",
bd3cd7c5
JD
345 "sys_socket", "syscall_entry_socket"]
346 # list of syscalls that can duplicate a FD
347 DUP_OPEN_SYSCALLS = ["sys_fcntl", "syscall_entry_fcntl",
348 "sys_dup2", "syscall_entry_dup2"]
349 SYNC_SYSCALLS = ["sys_sync", "syscall_entry_sync",
350 "sys_sync_file_range", "syscall_entry_sync_file_range",
351 "sys_fsync", "syscall_entry_fsync",
352 "sys_fdatasync", "syscall_entry_fdatasync"]
353 # merge the 3 open lists
354 OPEN_SYSCALLS = DISK_OPEN_SYSCALLS + NET_OPEN_SYSCALLS + DUP_OPEN_SYSCALLS
355 # list of syscalls that close a FD (in the "fd =" field)
356 CLOSE_SYSCALLS = ["sys_close", "syscall_entry_close"]
357 # list of syscall that read on a FD, value in the exit_syscall following
358 READ_SYSCALLS = ["sys_read", "syscall_entry_read",
359 "sys_recvmsg", "syscall_entry_recvmsg",
360 "sys_recvfrom", "syscall_entry_recvfrom",
361 "sys_splice", "syscall_entry_splice",
362 "sys_readv", "syscall_entry_readv",
363 "sys_sendfile64", "syscall_entry_sendfile64"]
364 # list of syscall that write on a FD, value in the exit_syscall following
365 WRITE_SYSCALLS = ["sys_write", "syscall_entry_write",
366 "sys_sendmsg", "syscall_entry_sendmsg",
367 "sys_sendto", "syscall_entry_sendto",
368 "sys_writev", "syscall_entry_writev"]
21167679
JD
369 # All I/O related syscalls
370 IO_SYSCALLS = OPEN_SYSCALLS + CLOSE_SYSCALLS + READ_SYSCALLS + \
c437b3bd 371 WRITE_SYSCALLS + SYNC_SYSCALLS
bd3cd7c5
JD
372 # generic names assigned to special FDs, don't try to match these in the
373 # closed_fds dict
374 GENERIC_NAMES = ["unknown", "socket"]
375
376 def __init__():
377 pass
This page took 0.043016 seconds and 5 git commands to generate.