Fix: correct typo in author email address
[deliverable/lttng-analyses.git] / linuxautomaton / linuxautomaton / syscalls.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
a9c9a2a6
JD
25import socket
26import operator
27from linuxautomaton import sp, sv, common
49fcdb4f 28from babeltrace import CTFScope
a9c9a2a6
JD
29
30
31class IOCategory():
32 """Defines an enumeration mapping IO categories to integer values.
33 Used mainly to export syscall metadata (to JSON)."""
34
35 invalid = 0
36 # Can't use open as a name given that is is a built-in function
37 # TODO: find less stupid name
38 opn = 1
39 close = 2
40 read = 3
41 write = 4
42
43
44class SyscallsStateProvider(sp.StateProvider):
45 def __init__(self, state):
46 self.state = state
47 self.cpus = state.cpus
48 self.tids = state.tids
49 self.syscalls = state.syscalls
50 self.pending_syscalls = state.pending_syscalls
51 self.syscalls["total"] = 0
52 self.dirty_pages = state.dirty_pages
53 cbs = {
54 'syscall_entry': self._process_syscall_entry,
55 'syscall_exit': self._process_syscall_exit,
12117527 56 'writeback_pages_written': self._process_writeback_pages_written,
30059169 57 'mm_vmscan_wakeup_kswapd': self._process_mm_vmscan_wakeup_kswapd,
2f163c78 58 'mm_page_free': self._process_mm_page_free,
a9c9a2a6
JD
59 }
60 self._register_cbs(cbs)
61
62 def process_event(self, ev):
63 self._process_event_cb(ev)
64
65 def get_syscall_category(self, name):
66 """Receives a syscall name and returns an enum value
67 representing its IO category (open, close, read, or write)"
68
69 This is used to produce json data for visualization"""
70
71 if name in sv.SyscallConsts.OPEN_SYSCALLS:
72 return IOCategory.opn
73 if name in sv.SyscallConsts.CLOSE_SYSCALLS:
74 return IOCategory.close
75 if name in sv.SyscallConsts.READ_SYSCALLS:
76 return IOCategory.read
77 if name in sv.SyscallConsts.WRITE_SYSCALLS:
78 return IOCategory.write
79
80 return IOCategory.invalid
81
82 def get_fd_type(self, name, family):
83 if name in sv.SyscallConsts.NET_OPEN_SYSCALLS:
84 if family in sv.SyscallConsts.INET_FAMILIES:
85 return sv.FDType.net
86 if family in sv.SyscallConsts.DISK_FAMILIES:
87 return sv.FDType.disk
88
89 if name in sv.SyscallConsts.DISK_OPEN_SYSCALLS:
90 return sv.FDType.disk
91
92 return sv.FDType.unknown
93
94 def global_syscall_entry(self, name):
95 if name not in self.syscalls:
96 s = sv.Syscall()
97 s.name = name
98 s.count = 0
99 self.syscalls[name] = s
100 else:
101 s = self.syscalls[name]
102 s.count += 1
103 self.syscalls["total"] += 1
104
7cc161dc
JD
105 def override_name(self, name, event):
106 if name in ["syscall_entry_epoll_ctl"]:
107 if event["op"] == 1:
108 name = "%s-ADD" % (name)
109 elif event["op"] == 2:
110 name = "%s-DEL" % (name)
111 elif event["op"] == 3:
112 name = "%s-MODE" % (name)
113 return name
114
21167679 115 def per_tid_syscall_entry(self, name, cpu_id, event):
a9c9a2a6
JD
116 # we don't know which process is currently on this CPU
117 if cpu_id not in self.cpus:
118 return
119 c = self.cpus[cpu_id]
120 if c.current_tid == -1:
121 return
122 t = self.tids[c.current_tid]
123 t.total_syscalls += 1
595f478e 124 name = self.override_name(name, event)
a9c9a2a6
JD
125 if name not in t.syscalls:
126 s = sv.Syscall()
127 s.name = name
128 t.syscalls[name] = s
129 else:
130 s = t.syscalls[name]
131 s.count += 1
21167679
JD
132 current_syscall = t.current_syscall
133 current_syscall["name"] = name
134 current_syscall["start"] = event.timestamp
595f478e 135 self.global_syscall_entry(name)
a9c9a2a6
JD
136
137 def track_open(self, name, proc, event, cpu):
138 self.tids[cpu.current_tid].current_syscall = {}
139 current_syscall = self.tids[cpu.current_tid].current_syscall
140 if name in sv.SyscallConsts.DISK_OPEN_SYSCALLS:
141 current_syscall["filename"] = event["filename"]
142 if event["flags"] & common.O_CLOEXEC == common.O_CLOEXEC:
143 current_syscall["cloexec"] = 1
144 elif name in ["sys_accept", "syscall_entry_accept"]:
145 if "family" in event.keys() and event["family"] == socket.AF_INET:
146 ipport = "%s:%d" % (common.get_v4_addr_str(event["v4addr"]),
147 event["sport"])
148 current_syscall["filename"] = ipport
149 else:
150 current_syscall["filename"] = "socket"
151 elif name in sv.SyscallConsts.NET_OPEN_SYSCALLS:
152 current_syscall["filename"] = "socket"
153 elif name in ["sys_dup2", "syscall_entry_dup2"]:
154 newfd = event["newfd"]
155 oldfd = event["oldfd"]
156 if newfd in proc.fds.keys():
157 self.close_fd(proc, newfd)
158 if oldfd in proc.fds.keys():
159 current_syscall["filename"] = proc.fds[oldfd].filename
160 current_syscall["fdtype"] = proc.fds[oldfd].fdtype
161 else:
162 current_syscall["filename"] = ""
163 elif name in ["sys_fcntl", "syscall_entry_fcntl"]:
164 # F_DUPsv.FD
165 if event["cmd"] != 0:
166 return
167 oldfd = event["fd"]
168 if oldfd in proc.fds.keys():
169 current_syscall["filename"] = proc.fds[oldfd].filename
170 current_syscall["fdtype"] = proc.fds[oldfd].fdtype
171 else:
172 current_syscall["filename"] = ""
173
174 if name in sv.SyscallConsts.NET_OPEN_SYSCALLS and \
175 "family" in event.keys():
176 family = event["family"]
177 current_syscall["family"] = family
178 else:
179 family = socket.AF_UNSPEC
180 current_syscall["family"] = family
181
182 current_syscall["name"] = name
183 current_syscall["start"] = event.timestamp
184 current_syscall["fdtype"] = self.get_fd_type(name, family)
185
186 def close_fd(self, proc, fd):
187 filename = proc.fds[fd].filename
188 if filename not in sv.SyscallConsts.GENERIC_NAMES \
189 and filename in proc.closed_fds.keys():
190 f = proc.closed_fds[filename]
191 f.close += 1
192 f.net_read += proc.fds[fd].net_read
193 f.disk_read += proc.fds[fd].disk_read
194 f.net_write += proc.fds[fd].net_write
195 f.disk_write += proc.fds[fd].disk_write
196 else:
197 proc.closed_fds[filename] = proc.fds[fd]
198 proc.closed_fds[filename].close = 1
199# print("Close sv.FD %s in %d (%d, %d, %d, %d)" %
200# (filename, proc.tid, proc.fds[fd].read, proc.fds[fd].write,
201# proc.fds[fd].open, proc.fds[fd].close))
202 proc.fds.pop(fd, None)
203
204 def track_close(self, name, proc, event, cpu):
205 fd = event["fd"]
206 if fd not in proc.fds.keys():
207 return
208
209 tid = self.tids[cpu.current_tid]
210 tid.current_syscall = {}
211 current_syscall = tid.current_syscall
212 current_syscall["filename"] = proc.fds[fd].filename
213 current_syscall["name"] = name
214 current_syscall["start"] = event.timestamp
215
216 self.close_fd(proc, fd)
217
49fcdb4f
JD
218 def _fix_context_pid(self, event, t):
219 for context in event.field_list_with_scope(
220 CTFScope.STREAM_EVENT_CONTEXT):
221 if context != "pid":
222 continue
223 # make sure the "pid" field is not also in the event
224 # payload, otherwise we might clash
225 for context in event.field_list_with_scope(
226 CTFScope.EVENT_FIELDS):
227 if context == "pid":
228 return
229 if t.pid == -1:
230 t.pid == event["pid"]
231 if event["pid"] != t.tid:
232 t.pid = event["pid"]
233 p = sv.Process()
234 p.tid = t.pid
235 p.pid = t.pid
236 p.comm = t.comm
237 self.tids[p.pid] = p
238
a9c9a2a6
JD
239 def track_fds(self, name, event, cpu_id):
240 # we don't know which process is currently on this CPU
241 ret_string = ""
242 if cpu_id not in self.cpus:
243 return
244 c = self.cpus[cpu_id]
245 if c.current_tid == -1:
246 return
247 t = self.tids[c.current_tid]
248 # check if we can fix the pid from a context
49fcdb4f 249 self._fix_context_pid(event, t)
a9c9a2a6
JD
250 # if it's a thread, we want the parent
251 if t.pid != -1 and t.tid != t.pid:
252 t = self.tids[t.pid]
253 if name in sv.SyscallConsts.OPEN_SYSCALLS:
254 self.track_open(name, t, event, c)
255 elif name in sv.SyscallConsts.CLOSE_SYSCALLS:
256 ret_string = "%s %s(%d)" % \
257 (common.ns_to_hour_nsec(event.timestamp),
258 name, event["fd"])
259 self.track_close(name, t, event, c)
260 # when a connect occurs, no new sv.FD is returned, but we can fix
261 # the "filename" if we have the destination info
262 elif name in ["sys_connect", "syscall_entry_connect"] \
263 and "family" in event.keys():
264 if event["family"] == socket.AF_INET:
69502021 265 fd = self.get_fd(t, event["fd"], event)
a9c9a2a6
JD
266 ipport = "%s:%d" % (common.get_v4_addr_str(event["v4addr"]),
267 event["dport"])
268 fd.filename = ipport
269 return ret_string
270
69502021 271 def get_fd(self, proc, fd, event):
a9c9a2a6
JD
272 if fd not in proc.fds.keys():
273 f = sv.FD()
274 f.fd = fd
275 f.filename = "unknown (origin not found)"
276 proc.fds[fd] = f
277 else:
278 f = proc.fds[fd]
44823c31
AB
279
280 proc.track_chrono_fd(fd, f.filename, f.fdtype, event.timestamp)
281
a9c9a2a6
JD
282 return f
283
284 def track_sync(self, name, event, cpu_id):
285 # we don't know which process is currently on this CPU
286 if cpu_id not in self.cpus:
287 return
288 c = self.cpus[cpu_id]
289 if c.current_tid == -1:
290 return
291 t = self.tids[c.current_tid]
292 self.pending_syscalls.append(t)
293 # if it's a thread, we want the parent
294 if t.pid != -1 and t.tid != t.pid:
295 t = self.tids[t.pid]
296 current_syscall = self.tids[c.current_tid].current_syscall
297 current_syscall["name"] = name
298 current_syscall["start"] = event.timestamp
299 if name not in ["sys_sync", "syscall_entry_sync"]:
300 fd = event["fd"]
69502021 301 f = self.get_fd(t, fd, event)
a9c9a2a6
JD
302 current_syscall["fd"] = f
303 current_syscall["filename"] = f.filename
304
305 def track_read_write(self, name, event, cpu_id):
306 # we don't know which process is currently on this CPU
307 if cpu_id not in self.cpus:
308 return
309 c = self.cpus[cpu_id]
310 if c.current_tid == -1:
311 return
312 t = self.tids[c.current_tid]
313 self.pending_syscalls.append(t)
314 # if it's a thread, we want the parent
315 if t.pid != -1 and t.tid != t.pid:
316 t = self.tids[t.pid]
317 current_syscall = self.tids[c.current_tid].current_syscall
318 current_syscall["name"] = name
319 current_syscall["start"] = event.timestamp
320 if name in ["sys_splice", "syscall_entry_splice"]:
69502021
AB
321 current_syscall["fd_in"] = self.get_fd(t, event["fd_in"], event)
322 current_syscall["fd_out"] = self.get_fd(t, event["fd_out"], event)
a9c9a2a6
JD
323 current_syscall["count"] = event["len"]
324 current_syscall["filename"] = current_syscall["fd_in"].filename
325 return
326 elif name in ["sys_sendfile64", "syscall_entry_sendfile64"]:
69502021
AB
327 current_syscall["fd_in"] = self.get_fd(t, event["in_fd"], event)
328 current_syscall["fd_out"] = self.get_fd(t, event["out_fd"], event)
a9c9a2a6
JD
329 current_syscall["count"] = event["count"]
330 current_syscall["filename"] = current_syscall["fd_in"].filename
331 return
332 fd = event["fd"]
69502021 333 f = self.get_fd(t, fd, event)
a9c9a2a6
JD
334 current_syscall["fd"] = f
335 if name in ["sys_writev", "syscall_entry_writev",
336 "sys_readv", "syscall_entry_readv"]:
337 current_syscall["count"] = event["vlen"]
338 elif name in ["sys_recvfrom", "syscall_entry_recvfrom"]:
339 current_syscall["count"] = event["size"]
340 elif name in ["sys_recvmsg", "syscall_entry_recvmsg",
341 "sys_sendmsg", "syscall_entry_sendmsg"]:
342 current_syscall["count"] = ""
343 elif name in ["sys_sendto", "syscall_entry_sendto"]:
344 current_syscall["count"] = event["len"]
345 else:
346 try:
347 current_syscall["count"] = event["count"]
348 except:
349 print("Missing count argument for syscall",
350 current_syscall["name"])
351 current_syscall["count"] = 0
352
353 current_syscall["filename"] = f.filename
354
355 def add_tid_fd(self, event, cpu):
356 ret = event["ret"]
357 t = self.tids[cpu.current_tid]
358 # if it's a thread, we want the parent
359 if t.pid != -1 and t.tid != t.pid:
360 t = self.tids[t.pid]
361 current_syscall = self.tids[cpu.current_tid].current_syscall
362
363 name = current_syscall["filename"]
364 if name not in sv.SyscallConsts.GENERIC_NAMES \
365 and name in t.closed_fds.keys():
366 fd = t.closed_fds[name]
367 fd.open += 1
368 else:
369 fd = sv.FD()
370 fd.filename = name
371 if current_syscall["name"] in sv.SyscallConsts.NET_OPEN_SYSCALLS:
372 fd.family = current_syscall["family"]
373 if fd.family in sv.SyscallConsts.INET_FAMILIES:
374 fd.fdtype = sv.FDType.net
375 fd.open = 1
376 if ret >= 0:
377 fd.fd = ret
378 else:
379 return
380 if "cloexec" in current_syscall.keys():
381 fd.cloexec = 1
382 t.fds[fd.fd] = fd
383
44823c31 384 t.track_chrono_fd(fd.fd, fd.filename, fd.fdtype, event.timestamp)
31d9c53b 385
a9c9a2a6
JD
386 def read_append(self, fd, proc, count, rq):
387 rq.operation = sv.IORequest.OP_READ
388 rq.size = count
389 if fd.fdtype in [sv.FDType.net, sv.FDType.maybe_net]:
390 fd.net_read += count
391 proc.net_read += count
392 elif fd.fdtype == sv.FDType.disk:
393 fd.disk_read += count
394 proc.disk_read += count
395 else:
396 fd.unk_read += count
397 proc.unk_read += count
398 fd.read += count
399 proc.read += count
400
401 def write_append(self, fd, proc, count, rq):
402 rq.operation = sv.IORequest.OP_WRITE
403 rq.size = count
404 if fd.fdtype in [sv.FDType.net, sv.FDType.maybe_net]:
405 fd.net_write += count
406 proc.net_write += count
407 elif fd.fdtype == sv.FDType.disk:
408 fd.disk_write += count
409 proc.disk_write += count
410 else:
411 fd.unk_write += count
412 proc.unk_write += count
413 fd.write += count
414 proc.write += count
415
416 def track_read_write_return(self, name, ret, cpu):
417 if ret < 0:
418 # TODO: track errors
419 return
420 proc = self.tids[cpu.current_tid]
421 # if it's a thread, we want the parent
422 if proc.pid != -1 and proc.tid != proc.pid:
423 proc = self.tids[proc.pid]
424 current_syscall = self.tids[cpu.current_tid].current_syscall
425 if name in ["sys_splice", "syscall_entry_splice",
426 "sys_sendfile64", "syscall_entry_sendfile64"]:
427 self.read_append(current_syscall["fd_in"], proc, ret,
428 current_syscall["iorequest"])
429 self.write_append(current_syscall["fd_out"], proc, ret,
430 current_syscall["iorequest"])
431 elif name in sv.SyscallConsts.READ_SYSCALLS:
432 if ret > 0:
433 self.read_append(current_syscall["fd"], proc, ret,
434 current_syscall["iorequest"])
435 elif name in sv.SyscallConsts.WRITE_SYSCALLS:
436 if ret > 0:
437 self.write_append(current_syscall["fd"], proc, ret,
438 current_syscall["iorequest"])
439
440 def get_page_queue_stats(self, page_list):
441 processes = {}
442 for i in page_list:
443 procname = i[0].comm
444 tid = i[0].tid
445 filename = i[2]
446 if tid not in processes.keys():
447 processes[tid] = {}
448 processes[tid]["procname"] = procname
449 processes[tid]["count"] = 1
450 processes[tid]["files"] = {}
451 processes[tid]["files"][filename] = 1
452 else:
453 processes[tid]["count"] += 1
454 if filename not in processes[tid]["files"].keys():
455 processes[tid]["files"][filename] = 1
456 else:
457 processes[tid]["files"][filename] += 1
458 return processes
459
460 def print_page_table(self, event, pages):
461 spaces = (41 + 6) * " "
462 for i in pages.keys():
463 p = pages[i]
464 print("%s %s (%d): %d pages" % (spaces, p["procname"],
465 i, p["count"]))
466 files = sorted(p["files"].items(), key=operator.itemgetter(1),
467 reverse=True)
468 for f in files:
469 print("%s - %s : %d pages" % (spaces, f[0], f[1]))
470
471 def syscall_clear_pages(self, event, name, fd, current_syscall, tid):
472 cleaned = []
473 if name in ["sys_sync", "syscall_entry_sync"]:
474 # remove all the pages
475 for i in range(len(self.dirty_pages["pages"])):
476 cleaned.append(self.dirty_pages["pages"].pop(0))
477 else:
478 # remove only the pages that belong to a specific proc/fd
479 for i in range(len(self.dirty_pages["pages"])):
480 proc = self.dirty_pages["pages"][i][0]
481 page_fd = self.dirty_pages["pages"][i][3]
482 if page_fd == fd and (tid.tid == proc.tid or
483 tid.pid == proc.pid):
484 cleaned.append(self.dirty_pages["pages"][i])
485 for i in cleaned:
486 self.dirty_pages["pages"].remove(i)
487 if len(cleaned) > 0:
488 current_syscall["pages_cleared"] = cleaned
489
490 def track_rw_latency(self, name, ret, c, ts, event):
491 current_syscall = self.tids[c.current_tid].current_syscall
492 rq = current_syscall["iorequest"]
493# FIXME: useless ?
494# if "start" not in current_syscall.keys():
495# return
496 rq.duration = (event.timestamp - current_syscall["start"])
497 rq.begin = current_syscall["start"]
498 rq.end = event.timestamp
499 rq.proc = self.tids[c.current_tid]
500 if "fd" in current_syscall.keys():
501 rq.fd = current_syscall["fd"]
502 r = current_syscall["fd"].iorequests
503 r.append(current_syscall["iorequest"])
504 elif "fd_in" in current_syscall.keys():
505 rq.fd = current_syscall["fd_in"]
506 # pages written during the latency
507 if "pages_written" in current_syscall.keys():
508 rq.page_written = current_syscall["pages_written"]
509 # dirty buffers during the latency
510 if "dirty" in current_syscall.keys():
511 rq.dirty = current_syscall["dirty"]
512 # alloc pages during the latency
513 if "alloc" in current_syscall.keys():
514 rq.page_alloc = current_syscall["alloc"]
515 # wakeup_kswapd during the latency
516 if "page_free" in current_syscall.keys():
517 rq.page_free = current_syscall["page_free"]
518 if "wakeup_kswapd" in current_syscall.keys():
519 rq.woke_kswapd = True
520 if name in sv.SyscallConsts.SYNC_SYSCALLS:
521# self.syscall_clear_pages(event, name, fd, current_syscall,
522# self.tids[c.current_tid])
523 if "pages_cleared" in current_syscall.keys():
524 rq.page_cleared = len(current_syscall["pages_cleared"])
525
21167679
JD
526 def _per_tid_syscall_exit(self, name, ret, event, c):
527 t = self.tids[c.current_tid]
3f195205
JD
528 if not name in t.syscalls:
529 return
21167679
JD
530 s = sv.SyscallEvent()
531 s.ret = ret
532 s.entry_ts = t.current_syscall["start"]
533 s.exit_ts = event.timestamp
534 s.duration = s.exit_ts - s.entry_ts
535 t_syscall = t.syscalls[name]
536 if t_syscall.min is None or t_syscall.min > s.duration:
537 t_syscall.min = s.duration
538 if t_syscall.max < s.duration:
539 t_syscall.max = s.duration
540 t_syscall.total_duration += s.duration
541 t_syscall.rq.append(s)
542
a9c9a2a6
JD
543 def _process_syscall_entry(self, event):
544 name = event.name
545 ret_string = ""
546 cpu_id = event["cpu_id"]
21167679 547 self.per_tid_syscall_entry(name, cpu_id, event)
a9c9a2a6
JD
548 ret_string = self.track_fds(name, event, cpu_id)
549 if name in sv.SyscallConsts.READ_SYSCALLS or \
550 name in sv.SyscallConsts.WRITE_SYSCALLS:
551 self.track_read_write(name, event, cpu_id)
552 if name in sv.SyscallConsts.SYNC_SYSCALLS:
553 self.track_sync(name, event, cpu_id)
554 return ret_string
555
556 def _process_syscall_exit(self, event):
557 cpu_id = event["cpu_id"]
558 ret_string = ""
559 if cpu_id not in self.cpus:
560 return
561 c = self.cpus[cpu_id]
562 if c.current_tid == -1:
563 return
564 current_syscall = self.tids[c.current_tid].current_syscall
565 if len(current_syscall.keys()) == 0:
566 return
567 name = current_syscall["name"]
568 ret = event["ret"]
21167679
JD
569 self._per_tid_syscall_exit(name, ret, event, c)
570
571 if name not in sv.SyscallConsts.IO_SYSCALLS:
572 return
573
a9c9a2a6
JD
574 current_syscall["iorequest"] = sv.IORequest()
575 current_syscall["iorequest"].iotype = sv.IORequest.IO_SYSCALL
576 current_syscall["iorequest"].name = name
577 if name in sv.SyscallConsts.OPEN_SYSCALLS:
578 self.add_tid_fd(event, c)
579 ret_string = "%s %s(%s, fd = %d)" % (
580 common.ns_to_hour_nsec(current_syscall["start"]),
581 name, current_syscall["filename"], ret)
582 if ret < 0:
583 return ret_string
584 t = self.tids[c.current_tid]
69502021 585 current_syscall["fd"] = self.get_fd(t, ret, event)
a9c9a2a6
JD
586 current_syscall["count"] = 0
587 current_syscall["fd"].fdtype = current_syscall["fdtype"]
588 current_syscall["iorequest"].operation = sv.IORequest.OP_OPEN
589 self.track_rw_latency(name, ret, c,
590 event.timestamp, event)
591 elif name in sv.SyscallConsts.READ_SYSCALLS or \
592 name in sv.SyscallConsts.WRITE_SYSCALLS:
593 self.track_read_write_return(name, ret, c)
594 self.track_rw_latency(name, ret, c, event.timestamp, event)
595 elif name in sv.SyscallConsts.SYNC_SYSCALLS:
596 current_syscall["iorequest"].operation = sv.IORequest.OP_SYNC
597 self.track_rw_latency(name, ret, c, event.timestamp, event)
598 if name in ["sys_sync", "syscall_entry_sync"]:
599 t = self.tids[c.current_tid]
600 t.iorequests.append(current_syscall["iorequest"])
601 self.tids[c.current_tid].current_syscall = {}
602 if self.tids[c.current_tid] in self.pending_syscalls:
603 self.pending_syscalls.remove(self.tids[c.current_tid])
604 return ret_string
605
12117527 606 def _process_writeback_pages_written(self, event):
a9c9a2a6
JD
607 """writeback_pages_written"""
608 for c in self.cpus.values():
609 if c.current_tid <= 0:
610 continue
611 current_syscall = self.tids[c.current_tid].current_syscall
612 if len(current_syscall.keys()) == 0:
613 continue
614 current_syscall["pages_written"] = event["pages"]
615
30059169 616 def _process_mm_vmscan_wakeup_kswapd(self, event):
a9c9a2a6
JD
617 """mm_vmscan_wakeup_kswapd"""
618 cpu_id = event["cpu_id"]
619 if cpu_id not in self.cpus:
620 return
621 c = self.cpus[cpu_id]
622 if c.current_tid == -1:
623 return
624 current_syscall = self.tids[c.current_tid].current_syscall
625 if len(current_syscall.keys()) == 0:
626 return
627 current_syscall["wakeup_kswapd"] = 1
628
2f163c78 629 def _process_mm_page_free(self, event):
a9c9a2a6
JD
630 """mm_page_free"""
631 for c in self.cpus.values():
632 if c.current_tid <= 0:
633 continue
634 p = self.tids[c.current_tid]
635 # if the current process is kswapd0, we need to
636 # attribute the page freed to the process that
637 # woke it up.
638 if p.comm == "kswapd0" and p.prev_tid > 0:
639 p = self.tids[p.prev_tid]
640 current_syscall = p.current_syscall
641 if len(current_syscall.keys()) == 0:
642 continue
643 if "wakeup_kswapd" in current_syscall.keys():
644 if "page_free" in current_syscall.keys():
645 current_syscall["page_free"] += 1
646 else:
647 current_syscall["page_free"] = 1
This page took 0.047259 seconds and 5 git commands to generate.