blob: 2faee505665ffbd7f0c398e147546dbef98971a7 [file] [log] [blame]
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -05001#!/usr/bin/env python
2#
3# syscount Summarize syscall counts and latencies.
4#
5# USAGE: syscount [-p PID] [-i INTERVAL] [-T TOP] [-x] [-L] [-m] [-P] [-l]
6#
7# Copyright 2017, Sasha Goldshtein.
8# Licensed under the Apache License, Version 2.0 (the "License")
9#
10# 15-Feb-2017 Sasha Goldshtein Created this.
11
12from bcc import BPF
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -050013from time import sleep, strftime
14import argparse
Sasha Goldshtein65453902017-03-26 13:06:51 +000015import itertools
Sasha Goldshtein51803bf2017-03-09 13:43:27 +000016import subprocess
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -050017import sys
Sandipan Dasa068a032017-10-10 14:46:29 +053018import platform
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -050019
Sasha Goldshtein65453902017-03-26 13:06:51 +000020if sys.version_info.major < 3:
21 izip_longest = itertools.izip_longest
22else:
23 izip_longest = itertools.zip_longest
24
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -050025#
26# Syscall table for Linux x86_64, not very recent.
27# Automatically generated from strace/linux/x86_64/syscallent.h using the
28# following command:
29#
30# cat syscallent.h | awk -F, '{ gsub(/[ \t"}]/, "", $4);
31# gsub(/[ \t/*]/, "", $5);
32# print " "$5": \""$4"\","; }
Paul Chaignon956ca1c2017-03-04 20:07:56 +010033# BEGIN { print "syscalls = {" }
34# END { print "}" }'
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -050035#
36syscalls = {
37 0: "read",
38 1: "write",
39 2: "open",
40 3: "close",
41 4: "stat",
42 5: "fstat",
43 6: "lstat",
44 7: "poll",
45 8: "lseek",
46 9: "mmap",
47 10: "mprotect",
48 11: "munmap",
49 12: "brk",
50 13: "rt_sigaction",
51 14: "rt_sigprocmask",
52 15: "rt_sigreturn",
53 16: "ioctl",
54 17: "pread",
55 18: "pwrite",
56 19: "readv",
57 20: "writev",
58 21: "access",
59 22: "pipe",
60 23: "select",
61 24: "sched_yield",
62 25: "mremap",
63 26: "msync",
64 27: "mincore",
65 28: "madvise",
66 29: "shmget",
67 30: "shmat",
68 31: "shmctl",
69 32: "dup",
70 33: "dup2",
71 34: "pause",
72 35: "nanosleep",
73 36: "getitimer",
74 37: "alarm",
75 38: "setitimer",
76 39: "getpid",
77 40: "sendfile",
78 41: "socket",
79 42: "connect",
80 43: "accept",
81 44: "sendto",
82 45: "recvfrom",
83 46: "sendmsg",
84 47: "recvmsg",
85 48: "shutdown",
86 49: "bind",
87 50: "listen",
88 51: "getsockname",
89 52: "getpeername",
90 53: "socketpair",
91 54: "setsockopt",
92 55: "getsockopt",
93 56: "clone",
94 57: "fork",
95 58: "vfork",
96 59: "execve",
97 60: "_exit",
98 61: "wait4",
99 62: "kill",
100 63: "uname",
101 64: "semget",
102 65: "semop",
103 66: "semctl",
104 67: "shmdt",
105 68: "msgget",
106 69: "msgsnd",
107 70: "msgrcv",
108 71: "msgctl",
109 72: "fcntl",
110 73: "flock",
111 74: "fsync",
112 75: "fdatasync",
113 76: "truncate",
114 77: "ftruncate",
115 78: "getdents",
116 79: "getcwd",
117 80: "chdir",
118 81: "fchdir",
119 82: "rename",
120 83: "mkdir",
121 84: "rmdir",
122 85: "creat",
123 86: "link",
124 87: "unlink",
125 88: "symlink",
126 89: "readlink",
127 90: "chmod",
128 91: "fchmod",
129 92: "chown",
130 93: "fchown",
131 94: "lchown",
132 95: "umask",
133 96: "gettimeofday",
134 97: "getrlimit",
135 98: "getrusage",
136 99: "sysinfo",
137 100: "times",
138 101: "ptrace",
139 102: "getuid",
140 103: "syslog",
141 104: "getgid",
142 105: "setuid",
143 106: "setgid",
144 107: "geteuid",
145 108: "getegid",
146 109: "setpgid",
147 110: "getppid",
148 111: "getpgrp",
149 112: "setsid",
150 113: "setreuid",
151 114: "setregid",
152 115: "getgroups",
153 116: "setgroups",
154 117: "setresuid",
155 118: "getresuid",
156 119: "setresgid",
157 120: "getresgid",
158 121: "getpgid",
159 122: "setfsuid",
160 123: "setfsgid",
161 124: "getsid",
162 125: "capget",
163 126: "capset",
164 127: "rt_sigpending",
165 128: "rt_sigtimedwait",
166 129: "rt_sigqueueinfo",
167 130: "rt_sigsuspend",
168 131: "sigaltstack",
169 132: "utime",
170 133: "mknod",
171 134: "uselib",
172 135: "personality",
173 136: "ustat",
174 137: "statfs",
175 138: "fstatfs",
176 139: "sysfs",
177 140: "getpriority",
178 141: "setpriority",
179 142: "sched_setparam",
180 143: "sched_getparam",
181 144: "sched_setscheduler",
182 145: "sched_getscheduler",
183 146: "sched_get_priority_max",
184 147: "sched_get_priority_min",
185 148: "sched_rr_get_interval",
186 149: "mlock",
187 150: "munlock",
188 151: "mlockall",
189 152: "munlockall",
190 153: "vhangup",
191 154: "modify_ldt",
192 155: "pivot_root",
193 156: "_sysctl",
194 157: "prctl",
195 158: "arch_prctl",
196 159: "adjtimex",
197 160: "setrlimit",
198 161: "chroot",
199 162: "sync",
200 163: "acct",
201 164: "settimeofday",
202 165: "mount",
203 166: "umount",
204 167: "swapon",
205 168: "swapoff",
206 169: "reboot",
207 170: "sethostname",
208 171: "setdomainname",
209 172: "iopl",
210 173: "ioperm",
211 174: "create_module",
212 175: "init_module",
213 176: "delete_module",
214 177: "get_kernel_syms",
215 178: "query_module",
216 179: "quotactl",
217 180: "nfsservctl",
218 181: "getpmsg",
219 182: "putpmsg",
220 183: "afs_syscall",
221 184: "tuxcall",
222 185: "security",
223 186: "gettid",
224 187: "readahead",
225 188: "setxattr",
226 189: "lsetxattr",
227 190: "fsetxattr",
228 191: "getxattr",
229 192: "lgetxattr",
230 193: "fgetxattr",
231 194: "listxattr",
232 195: "llistxattr",
233 196: "flistxattr",
234 197: "removexattr",
235 198: "lremovexattr",
236 199: "fremovexattr",
237 200: "tkill",
238 201: "time",
239 202: "futex",
240 203: "sched_setaffinity",
241 204: "sched_getaffinity",
242 205: "set_thread_area",
243 206: "io_setup",
244 207: "io_destroy",
245 208: "io_getevents",
246 209: "io_submit",
247 210: "io_cancel",
248 211: "get_thread_area",
249 212: "lookup_dcookie",
250 213: "epoll_create",
251 214: "epoll_ctl_old",
252 215: "epoll_wait_old",
253 216: "remap_file_pages",
254 217: "getdents64",
255 218: "set_tid_address",
256 219: "restart_syscall",
257 220: "semtimedop",
258 221: "fadvise64",
259 222: "timer_create",
260 223: "timer_settime",
261 224: "timer_gettime",
262 225: "timer_getoverrun",
263 226: "timer_delete",
264 227: "clock_settime",
265 228: "clock_gettime",
266 229: "clock_getres",
267 230: "clock_nanosleep",
268 231: "exit_group",
269 232: "epoll_wait",
270 233: "epoll_ctl",
271 234: "tgkill",
272 235: "utimes",
273 236: "vserver",
274 237: "mbind",
275 238: "set_mempolicy",
276 239: "get_mempolicy",
277 240: "mq_open",
278 241: "mq_unlink",
279 242: "mq_timedsend",
280 243: "mq_timedreceive",
281 244: "mq_notify",
282 245: "mq_getsetattr",
283 246: "kexec_load",
284 247: "waitid",
285 248: "add_key",
286 249: "request_key",
287 250: "keyctl",
288 251: "ioprio_set",
289 252: "ioprio_get",
290 253: "inotify_init",
291 254: "inotify_add_watch",
292 255: "inotify_rm_watch",
293 256: "migrate_pages",
294 257: "openat",
295 258: "mkdirat",
296 259: "mknodat",
297 260: "fchownat",
298 261: "futimesat",
299 262: "newfstatat",
300 263: "unlinkat",
301 264: "renameat",
302 265: "linkat",
303 266: "symlinkat",
304 267: "readlinkat",
305 268: "fchmodat",
306 269: "faccessat",
307 270: "pselect6",
308 271: "ppoll",
309 272: "unshare",
310 273: "set_robust_list",
311 274: "get_robust_list",
312 275: "splice",
313 276: "tee",
314 277: "sync_file_range",
315 278: "vmsplice",
316 279: "move_pages",
317 280: "utimensat",
318 281: "epoll_pwait",
319 282: "signalfd",
320 283: "timerfd_create",
321 284: "eventfd",
322 285: "fallocate",
323 286: "timerfd_settime",
324 287: "timerfd_gettime",
325 288: "accept4",
326 289: "signalfd4",
327 290: "eventfd2",
328 291: "epoll_create1",
329 292: "dup3",
330 293: "pipe2",
331 294: "inotify_init1",
332 295: "preadv",
333 296: "pwritev",
334 297: "rt_tgsigqueueinfo",
335 298: "perf_event_open",
336 299: "recvmmsg",
337 300: "fanotify_init",
338 301: "fanotify_mark",
339 302: "prlimit64",
340 303: "name_to_handle_at",
341 304: "open_by_handle_at",
342 305: "clock_adjtime",
343 306: "syncfs",
344 307: "sendmmsg",
345 308: "setns",
346 309: "getcpu",
347 310: "process_vm_readv",
348 311: "process_vm_writev",
349 312: "kcmp",
350 313: "finit_module",
351}
352
Sasha Goldshtein51803bf2017-03-09 13:43:27 +0000353# Try to use ausyscall if it is available, because it can give us an up-to-date
354# list of syscalls for various architectures, rather than the x86-64 hardcoded
355# list above.
356def parse_syscall(line):
357 parts = line.split()
358 return (int(parts[0]), parts[1].strip())
359
360try:
361 # Skip the first line, which is a header. The rest of the lines are simply
362 # SYSCALL_NUM\tSYSCALL_NAME pairs.
363 out = subprocess.check_output('ausyscall --dump | tail -n +2', shell=True)
364 syscalls = dict(map(parse_syscall, out.strip().split('\n')))
365except Exception as e:
Sandipan Dasa068a032017-10-10 14:46:29 +0530366 if platform.machine() == "x86_64":
367 pass
368 else:
369 raise Exception("ausyscall: command not found")
Sasha Goldshtein51803bf2017-03-09 13:43:27 +0000370
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -0500371parser = argparse.ArgumentParser(
372 description="Summarize syscall counts and latencies.")
373parser.add_argument("-p", "--pid", type=int, help="trace only this pid")
374parser.add_argument("-i", "--interval", type=int,
375 help="print summary at this interval (seconds)")
376parser.add_argument("-T", "--top", type=int, default=10,
377 help="print only the top syscalls by count or latency")
378parser.add_argument("-x", "--failures", action="store_true",
379 help="trace only failed syscalls (return < 0)")
380parser.add_argument("-L", "--latency", action="store_true",
381 help="collect syscall latency")
382parser.add_argument("-m", "--milliseconds", action="store_true",
383 help="display latency in milliseconds (default: microseconds)")
384parser.add_argument("-P", "--process", action="store_true",
385 help="count by process and not by syscall")
386parser.add_argument("-l", "--list", action="store_true",
387 help="print list of recognized syscalls and exit")
388args = parser.parse_args()
389
390if args.list:
391 for grp in izip_longest(*(iter(sorted(syscalls.values())),) * 4):
392 print(" ".join(["%-20s" % s for s in grp if s is not None]))
393 sys.exit(0)
394
395text = """
396#ifdef LATENCY
397struct data_t {
398 u64 count;
399 u64 total_ns;
400};
401
402BPF_HASH(start, u64, u64);
403BPF_HASH(data, u32, struct data_t);
404#else
405BPF_HASH(data, u32, u64);
406#endif
407
408#ifdef LATENCY
409TRACEPOINT_PROBE(raw_syscalls, sys_enter) {
410 u64 pid_tgid = bpf_get_current_pid_tgid();
411
412#ifdef FILTER_PID
413 if (pid_tgid >> 32 != FILTER_PID)
414 return 0;
415#endif
416
417 u64 t = bpf_ktime_get_ns();
418 start.update(&pid_tgid, &t);
419 return 0;
420}
421#endif
422
423TRACEPOINT_PROBE(raw_syscalls, sys_exit) {
424 u64 pid_tgid = bpf_get_current_pid_tgid();
425
426#ifdef FILTER_PID
427 if (pid_tgid >> 32 != FILTER_PID)
428 return 0;
429#endif
430
431#ifdef FILTER_FAILED
432 if (args->ret >= 0)
433 return 0;
434#endif
435
436#ifdef BY_PROCESS
437 u32 key = pid_tgid >> 32;
438#else
439 u32 key = args->id;
440#endif
441
442#ifdef LATENCY
443 struct data_t *val, zero = {};
444 u64 *start_ns = start.lookup(&pid_tgid);
445 if (!start_ns)
446 return 0;
447
448 val = data.lookup_or_init(&key, &zero);
449 val->count++;
450 val->total_ns = bpf_ktime_get_ns() - *start_ns;
451#else
452 u64 *val, zero = 0;
453 val = data.lookup_or_init(&key, &zero);
454 ++(*val);
455#endif
456 return 0;
457}
458"""
459
460if args.pid:
461 text = ("#define FILTER_PID %d\n" % args.pid) + text
462if args.failures:
463 text = "#define FILTER_FAILED\n" + text
464if args.latency:
465 text = "#define LATENCY\n" + text
466if args.process:
467 text = "#define BY_PROCESS\n" + text
468
469bpf = BPF(text=text)
470
471def print_stats():
472 if args.latency:
473 print_latency_stats()
474 else:
475 print_count_stats()
476
477agg_colname = "PID COMM" if args.process else "SYSCALL"
478time_colname = "TIME (ms)" if args.milliseconds else "TIME (us)"
479
480def comm_for_pid(pid):
481 try:
482 return open("/proc/%d/comm" % pid).read().strip()
483 except Exception:
484 return "[unknown]"
485
486def agg_colval(key):
487 if args.process:
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100488 return "%-6d %-15s" % (key.value, comm_for_pid(key.value))
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -0500489 else:
490 return syscalls.get(key.value, "[unknown: %d]" % key.value)
491
492def print_count_stats():
493 data = bpf["data"]
494 print("[%s]" % strftime("%H:%M:%S"))
495 print("%-22s %8s" % (agg_colname, "COUNT"))
496 for k, v in sorted(data.items(), key=lambda kv: -kv[1].value)[:args.top]:
497 if k.value == 0xFFFFFFFF:
498 continue # happens occasionally, we don't need it
499 print("%-22s %8d" % (agg_colval(k), v.value))
500 print("")
501 data.clear()
502
503def print_latency_stats():
504 data = bpf["data"]
505 print("[%s]" % strftime("%H:%M:%S"))
506 print("%-22s %8s %16s" % (agg_colname, "COUNT", time_colname))
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100507 for k, v in sorted(data.items(),
508 key=lambda kv: -kv[1].total_ns)[:args.top]:
Sasha Goldshtein8e583cc2017-02-09 10:11:50 -0500509 if k.value == 0xFFFFFFFF:
510 continue # happens occasionally, we don't need it
511 print(("%-22s %8d " + ("%16.6f" if args.milliseconds else "%16.3f")) %
512 (agg_colval(k), v.count,
513 v.total_ns / (1e6 if args.milliseconds else 1e3)))
514 print("")
515 data.clear()
516
517print("Tracing %ssyscalls, printing top %d... Ctrl+C to quit." %
518 ("failed " if args.failures else "", args.top))
519while True:
520 try:
521 sleep(args.interval or 999999999)
522 print_stats()
523 except KeyboardInterrupt:
524 if not args.interval:
525 print_stats()
526 break