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