blob: 0bc1414e0871183d796f44cec6f0521d003f535b [file] [log] [blame]
Alexey Ivanovcc01a9c2019-01-16 09:50:46 -08001#!/usr/bin/python
Sasha Goldshtein85384852016-02-12 01:29:39 -08002#
Sasha Goldshtein7df65da2016-02-14 05:12:27 -08003# argdist Trace a function and display a distribution of its
Sasha Goldshteinfd60d552016-03-01 12:15:34 -08004# parameter values as a histogram or frequency count.
Sasha Goldshtein85384852016-02-12 01:29:39 -08005#
Sasha Goldshtein4725a722016-10-18 20:54:47 +03006# USAGE: argdist [-h] [-p PID] [-z STRING_SIZE] [-i INTERVAL] [-n COUNT] [-v]
7# [-c] [-T TOP] [-C specifier] [-H specifier] [-I header]
Sasha Goldshtein85384852016-02-12 01:29:39 -08008#
9# Licensed under the Apache License, Version 2.0 (the "License")
10# Copyright (C) 2016 Sasha Goldshtein.
11
Sumanth Korikkar306080b2020-04-27 04:37:23 -050012from bcc import BPF, USDT, StrcmpRewrite
Sasha Goldshtein85384852016-02-12 01:29:39 -080013from time import sleep, strftime
14import argparse
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080015import re
Sasha Goldshteinc9551302016-02-21 02:21:46 -080016import traceback
Sasha Goldshteinfd60d552016-03-01 12:15:34 -080017import os
Sasha Goldshteinc9551302016-02-21 02:21:46 -080018import sys
Sasha Goldshtein85384852016-02-12 01:29:39 -080019
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070020class Probe(object):
Sasha Goldshtein85384852016-02-12 01:29:39 -080021 next_probe_index = 0
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -070022 streq_index = 0
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010023 aliases = {"$PID": "(bpf_get_current_pid_tgid() >> 32)"}
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080024
25 def _substitute_aliases(self, expr):
26 if expr is None:
27 return expr
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070028 for alias, subst in Probe.aliases.items():
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080029 expr = expr.replace(alias, subst)
30 return expr
Sasha Goldshtein85384852016-02-12 01:29:39 -080031
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080032 def _parse_signature(self):
33 params = map(str.strip, self.signature.split(','))
34 self.param_types = {}
35 for param in params:
36 # If the type is a pointer, the * can be next to the
37 # param name. Other complex types like arrays are not
38 # supported right now.
39 index = param.rfind('*')
40 index = index if index != -1 else param.rfind(' ')
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030041 param_type = param[0:index + 1].strip()
42 param_name = param[index + 1:].strip()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080043 self.param_types[param_name] = param_type
Sumanth Korikkar306080b2020-04-27 04:37:23 -050044 # Maintain list of user params. Then later decide to
45 # switch to bpf_probe_read or bpf_probe_read_user.
46 if "__user" in param_type.split():
47 self.probe_user_list.add(param_name)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080048
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070049 def _generate_entry(self):
50 self.entry_probe_func = self.probe_func_name + "_entry"
51 text = """
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080052int PROBENAME(struct pt_regs *ctx SIGNATURE)
53{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010054 u64 __pid_tgid = bpf_get_current_pid_tgid();
55 u32 __pid = __pid_tgid; // lower 32 bits
56 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080057 PID_FILTER
58 COLLECT
59 return 0;
60}
61"""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080062 text = text.replace("PROBENAME", self.entry_probe_func)
63 text = text.replace("SIGNATURE",
64 "" if len(self.signature) == 0 else ", " + self.signature)
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010065 text = text.replace("PID_FILTER", self._generate_pid_filter())
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080066 collect = ""
67 for pname in self.args_to_probe:
Sasha Goldshteine3501152016-02-13 03:56:29 -080068 param_hash = self.hashname_prefix + pname
69 if pname == "__latency":
70 collect += """
71u64 __time = bpf_ktime_get_ns();
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010072%s.update(&__pid, &__time);
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030073 """ % param_hash
Sasha Goldshteine3501152016-02-13 03:56:29 -080074 else:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010075 collect += "%s.update(&__pid, &%s);\n" % \
Sasha Goldshteine3501152016-02-13 03:56:29 -080076 (param_hash, pname)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080077 text = text.replace("COLLECT", collect)
78 return text
79
80 def _generate_entry_probe(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080081 # Any $entry(name) expressions result in saving that argument
82 # when entering the function.
83 self.args_to_probe = set()
84 regex = r"\$entry\((\w+)\)"
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080085 for expr in self.exprs:
86 for arg in re.finditer(regex, expr):
87 self.args_to_probe.add(arg.group(1))
Sasha Goldshteine3501152016-02-13 03:56:29 -080088 for arg in re.finditer(regex, self.filter):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080089 self.args_to_probe.add(arg.group(1))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080090 if any(map(lambda expr: "$latency" in expr, self.exprs)) or \
91 "$latency" in self.filter:
Sasha Goldshteine3501152016-02-13 03:56:29 -080092 self.args_to_probe.add("__latency")
93 self.param_types["__latency"] = "u64" # nanoseconds
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080094 for pname in self.args_to_probe:
95 if pname not in self.param_types:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030096 raise ValueError("$entry(%s): no such param" %
97 arg)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080098
99 self.hashname_prefix = "%s_param_" % self.probe_hash_name
100 text = ""
101 for pname in self.args_to_probe:
102 # Each argument is stored in a separate hash that is
103 # keyed by pid.
104 text += "BPF_HASH(%s, u32, %s);\n" % \
105 (self.hashname_prefix + pname,
106 self.param_types[pname])
107 text += self._generate_entry()
108 return text
109
110 def _generate_retprobe_prefix(self):
111 # After we're done here, there are __%s_val variables for each
112 # argument we needed to probe using $entry(name), and they all
113 # have values (which isn't necessarily the case if we missed
114 # the method entry probe).
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100115 text = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800116 self.param_val_names = {}
117 for pname in self.args_to_probe:
118 val_name = "__%s_val" % pname
119 text += "%s *%s = %s.lookup(&__pid);\n" % \
120 (self.param_types[pname], val_name,
121 self.hashname_prefix + pname)
122 text += "if (%s == 0) { return 0 ; }\n" % val_name
123 self.param_val_names[pname] = val_name
124 return text
125
126 def _replace_entry_exprs(self):
127 for pname, vname in self.param_val_names.items():
Sasha Goldshteine3501152016-02-13 03:56:29 -0800128 if pname == "__latency":
129 entry_expr = "$latency"
130 val_expr = "(bpf_ktime_get_ns() - *%s)" % vname
131 else:
132 entry_expr = "$entry(%s)" % pname
133 val_expr = "(*%s)" % vname
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800134 for i in range(0, len(self.exprs)):
135 self.exprs[i] = self.exprs[i].replace(
136 entry_expr, val_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800137 self.filter = self.filter.replace(entry_expr,
138 val_expr)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800139
140 def _attach_entry_probe(self):
141 if self.is_user:
142 self.bpf.attach_uprobe(name=self.library,
143 sym=self.function,
144 fn_name=self.entry_probe_func,
145 pid=self.pid or -1)
146 else:
147 self.bpf.attach_kprobe(event=self.function,
148 fn_name=self.entry_probe_func)
149
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800150 def _bail(self, error):
151 raise ValueError("error parsing probe '%s': %s" %
152 (self.raw_spec, error))
153
154 def _validate_specifier(self):
155 # Everything after '#' is the probe label, ignore it
156 spec = self.raw_spec.split('#')[0]
157 parts = spec.strip().split(':')
158 if len(parts) < 3:
159 self._bail("at least the probe type, library, and " +
160 "function signature must be specified")
161 if len(parts) > 6:
162 self._bail("extraneous ':'-separated parts detected")
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700163 if parts[0] not in ["r", "p", "t", "u"]:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300164 self._bail("probe type must be 'p', 'r', 't', or 'u'" +
165 " but got '%s'" % parts[0])
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000166 if re.match(r"\S+\(.*\)", parts[2]) is None:
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800167 self._bail(("function signature '%s' has an invalid " +
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800168 "format") % parts[2])
169
170 def _parse_expr_types(self, expr_types):
171 if len(expr_types) == 0:
172 self._bail("no expr types specified")
173 self.expr_types = expr_types.split(',')
174
175 def _parse_exprs(self, exprs):
176 if len(exprs) == 0:
177 self._bail("no exprs specified")
178 self.exprs = exprs.split(',')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800179
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000180 def _make_valid_identifier(self, ident):
181 return re.sub(r'[^A-Za-z0-9_]', '_', ident)
182
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300183 def __init__(self, tool, type, specifier):
184 self.usdt_ctx = None
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700185 self.streq_functions = ""
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300186 self.pid = tool.args.pid
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300187 self.cumulative = tool.args.cumulative or False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800188 self.raw_spec = specifier
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500189 self.probe_user_list = set()
190 self.bin_cmp = False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800191 self._validate_specifier()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800192
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800193 spec_and_label = specifier.split('#')
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800194 self.label = spec_and_label[1] \
195 if len(spec_and_label) == 2 else None
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800196
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800197 parts = spec_and_label[0].strip().split(':')
Sasha Goldshtein85384852016-02-12 01:29:39 -0800198 self.type = type # hist or freq
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800199 self.probe_type = parts[0]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800200 fparts = parts[2].split('(')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800201 self.function = fparts[0].strip()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800202 if self.probe_type == "t":
203 self.library = "" # kernel
204 self.tp_category = parts[1]
205 self.tp_event = self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700206 elif self.probe_type == "u":
207 self.library = parts[1]
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000208 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100209 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000210 (self.function, Probe.next_probe_index))
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300211 self._enable_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800212 else:
213 self.library = parts[1]
214 self.is_user = len(self.library) > 0
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800215 self.signature = fparts[1].strip()[:-1]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800216 self._parse_signature()
217
218 # If the user didn't specify an expression to probe, we probe
219 # the retval in a ret probe, or simply the value "1" otherwise.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800220 self.is_default_expr = len(parts) < 5
221 if not self.is_default_expr:
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800222 self._parse_expr_types(parts[3])
223 self._parse_exprs(parts[4])
224 if len(self.exprs) != len(self.expr_types):
225 self._bail("mismatched # of exprs and types")
226 if self.type == "hist" and len(self.expr_types) > 1:
227 self._bail("histograms can only have 1 expr")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800228 else:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800229 if not self.probe_type == "r" and self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800230 self._bail("histograms must have expr")
231 self.expr_types = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800232 ["u64" if not self.probe_type == "r" else "int"]
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800233 self.exprs = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800234 ["1" if not self.probe_type == "r" else "$retval"]
Sasha Goldshteine3501152016-02-13 03:56:29 -0800235 self.filter = "" if len(parts) != 6 else parts[5]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800236 self._substitute_exprs()
237
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800238 # Do we need to attach an entry probe so that we can collect an
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800239 # argument that is required for an exit (return) probe?
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800240 def check(expr):
241 keywords = ["$entry", "$latency"]
242 return any(map(lambda kw: kw in expr, keywords))
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800243 self.entry_probe_required = self.probe_type == "r" and \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800244 (any(map(check, self.exprs)) or check(self.filter))
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800245
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000246 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100247 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000248 (self.function, Probe.next_probe_index))
249 self.probe_hash_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100250 "%s_hash%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000251 (self.function, Probe.next_probe_index))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700252 Probe.next_probe_index += 1
253
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300254 def _enable_usdt_probe(self):
255 self.usdt_ctx = USDT(path=self.library, pid=self.pid)
256 self.usdt_ctx.enable_probe(
257 self.function, self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800258
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800259 def _substitute_exprs(self):
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800260 def repl(expr):
261 expr = self._substitute_aliases(expr)
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500262 rdict = StrcmpRewrite.rewrite_expr(expr,
263 self.bin_cmp, self.library,
264 self.probe_user_list, self.streq_functions,
265 Probe.streq_index)
266 expr = rdict["expr"]
267 self.streq_functions = rdict["streq_functions"]
268 Probe.streq_index = rdict["probeid"]
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530269 return expr.replace("$retval", "PT_REGS_RC(ctx)")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800270 for i in range(0, len(self.exprs)):
271 self.exprs[i] = repl(self.exprs[i])
272 self.filter = repl(self.filter)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800273
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800274 def _is_string(self, expr_type):
275 return expr_type == "char*" or expr_type == "char *"
Sasha Goldshtein85384852016-02-12 01:29:39 -0800276
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800277 def _generate_hash_field(self, i):
278 if self._is_string(self.expr_types[i]):
279 return "struct __string_t v%d;\n" % i
280 else:
281 return "%s v%d;\n" % (self.expr_types[i], i)
282
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300283 def _generate_usdt_arg_assignment(self, i):
284 expr = self.exprs[i]
285 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000286 arg_index = int(expr[3])
287 arg_ctype = self.usdt_ctx.get_probe_arg_ctype(
288 self.function, arg_index - 1)
289 return (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300290 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000291 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300292 else:
293 return ""
294
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800295 def _generate_field_assignment(self, i):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300296 text = self._generate_usdt_arg_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800297 if self._is_string(self.expr_types[i]):
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500298 if self.is_user or \
299 self.exprs[i] in self.probe_user_list:
300 probe_readfunc = "bpf_probe_read_user"
301 else:
302 probe_readfunc = "bpf_probe_read"
303 return (text + " %s(&__key.v%d.s," +
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700304 " sizeof(__key.v%d.s), (void *)%s);\n") % \
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500305 (probe_readfunc, i, i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800306 else:
Brendan Gregg4f88a942016-07-22 17:11:51 -0700307 return text + " __key.v%d = %s;\n" % \
308 (i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800309
310 def _generate_hash_decl(self):
311 if self.type == "hist":
312 return "BPF_HISTOGRAM(%s, %s);" % \
313 (self.probe_hash_name, self.expr_types[0])
314 else:
315 text = "struct %s_key_t {\n" % self.probe_hash_name
316 for i in range(0, len(self.expr_types)):
317 text += self._generate_hash_field(i)
318 text += "};\n"
319 text += "BPF_HASH(%s, struct %s_key_t, u64);\n" % \
320 (self.probe_hash_name, self.probe_hash_name)
321 return text
322
323 def _generate_key_assignment(self):
324 if self.type == "hist":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300325 return self._generate_usdt_arg_assignment(0) + \
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300326 ("%s __key = %s;\n" %
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300327 (self.expr_types[0], self.exprs[0]))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800328 else:
329 text = "struct %s_key_t __key = {};\n" % \
330 self.probe_hash_name
331 for i in range(0, len(self.exprs)):
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800332 text += self._generate_field_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800333 return text
334
335 def _generate_hash_update(self):
336 if self.type == "hist":
337 return "%s.increment(bpf_log2l(__key));" % \
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800338 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800339 else:
340 return "%s.increment(__key);" % self.probe_hash_name
341
342 def _generate_pid_filter(self):
343 # Kernel probes need to explicitly filter pid, because the
344 # attach interface doesn't support pid filtering
345 if self.pid is not None and not self.is_user:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100346 return "if (__tgid != %d) { return 0; }" % self.pid
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800347 else:
348 return ""
349
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800350 def generate_text(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800351 program = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700352 probe_text = """
353DATA_DECL
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300354 """ + (
355 "TRACEPOINT_PROBE(%s, %s)" %
356 (self.tp_category, self.tp_event)
357 if self.probe_type == "t"
358 else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700359{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100360 u64 __pid_tgid = bpf_get_current_pid_tgid();
361 u32 __pid = __pid_tgid; // lower 32 bits
362 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700363 PID_FILTER
364 PREFIX
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700365 KEY_EXPR
Akilesh Kailashb8269aa2020-05-11 11:54:26 -0700366 if (!(FILTER)) return 0;
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700367 COLLECT
368 return 0;
369}
370"""
371 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700372 signature = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800373
374 # If any entry arguments are probed in a ret probe, we need
375 # to generate an entry probe to collect them
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800376 if self.entry_probe_required:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800377 program += self._generate_entry_probe()
378 prefix += self._generate_retprobe_prefix()
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800379 # Replace $entry(paramname) with a reference to the
380 # value we collected when entering the function:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800381 self._replace_entry_exprs()
382
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300383 if self.probe_type == "p" and len(self.signature) > 0:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700384 # Only entry uprobes/kprobes can have user-specified
385 # signatures. Other probes force it to ().
386 signature = ", " + self.signature
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800387
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300388 program += probe_text.replace("PROBENAME",
389 self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800390 program = program.replace("SIGNATURE", signature)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800391 program = program.replace("PID_FILTER",
392 self._generate_pid_filter())
393
394 decl = self._generate_hash_decl()
395 key_expr = self._generate_key_assignment()
396 collect = self._generate_hash_update()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800397 program = program.replace("DATA_DECL", decl)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800398 program = program.replace("KEY_EXPR", key_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800399 program = program.replace("FILTER",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800400 "1" if len(self.filter) == 0 else self.filter)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800401 program = program.replace("COLLECT", collect)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800402 program = program.replace("PREFIX", prefix)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700403
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700404 return self.streq_functions + program
Sasha Goldshtein85384852016-02-12 01:29:39 -0800405
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700406 def _attach_u(self):
407 libpath = BPF.find_library(self.library)
408 if libpath is None:
Sasha Goldshteinec679712016-10-04 18:33:36 +0300409 libpath = BPF.find_exe(self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700410 if libpath is None or len(libpath) == 0:
Sasha Goldshtein5a1d2e32016-03-30 08:14:44 -0700411 self._bail("unable to find library %s" % self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700412
Brendan Gregg4f88a942016-07-22 17:11:51 -0700413 if self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700414 self.bpf.attach_uretprobe(name=libpath,
415 sym=self.function,
416 fn_name=self.probe_func_name,
417 pid=self.pid or -1)
418 else:
419 self.bpf.attach_uprobe(name=libpath,
420 sym=self.function,
421 fn_name=self.probe_func_name,
422 pid=self.pid or -1)
423
424 def _attach_k(self):
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300425 if self.probe_type == "t":
426 pass # Nothing to do for tracepoints
427 elif self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700428 self.bpf.attach_kretprobe(event=self.function,
429 fn_name=self.probe_func_name)
430 else:
431 self.bpf.attach_kprobe(event=self.function,
432 fn_name=self.probe_func_name)
433
Sasha Goldshtein85384852016-02-12 01:29:39 -0800434 def attach(self, bpf):
435 self.bpf = bpf
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300436 if self.probe_type == "u":
437 return
Sasha Goldshtein85384852016-02-12 01:29:39 -0800438 if self.is_user:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700439 self._attach_u()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800440 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700441 self._attach_k()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800442 if self.entry_probe_required:
443 self._attach_entry_probe()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800444
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800445 def _v2s(self, v):
446 # Most fields can be converted with plain str(), but strings
447 # are wrapped in a __string_t which has an .s field
448 if "__string_t" in type(v).__name__:
449 return str(v.s)
450 return str(v)
451
452 def _display_expr(self, i):
453 # Replace ugly latency calculation with $latency
454 expr = self.exprs[i].replace(
455 "(bpf_ktime_get_ns() - *____latency_val)", "$latency")
456 # Replace alias values back with the alias name
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700457 for alias, subst in Probe.aliases.items():
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800458 expr = expr.replace(subst, alias)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800459 # Replace retval expression with $retval
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530460 expr = expr.replace("PT_REGS_RC(ctx)", "$retval")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800461 # Replace ugly (*__param_val) expressions with param name
462 return re.sub(r"\(\*__(\w+)_val\)", r"\1", expr)
463
464 def _display_key(self, key):
465 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800466 if not self.probe_type == "r":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800467 return "total calls"
468 else:
469 return "retval = %s" % str(key.v0)
470 else:
471 # The key object has v0, ..., vk fields containing
472 # the values of the expressions from self.exprs
473 def str_i(i):
474 key_i = self._v2s(getattr(key, "v%d" % i))
475 return "%s = %s" % \
476 (self._display_expr(i), key_i)
477 return ", ".join(map(str_i, range(0, len(self.exprs))))
478
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800479 def display(self, top):
Sasha Goldshtein85384852016-02-12 01:29:39 -0800480 data = self.bpf.get_table(self.probe_hash_name)
481 if self.type == "freq":
Sasha Goldshteine3501152016-02-13 03:56:29 -0800482 print(self.label or self.raw_spec)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800483 print("\t%-10s %s" % ("COUNT", "EVENT"))
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300484 sdata = sorted(data.items(), key=lambda p: p[1].value)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800485 if top is not None:
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300486 sdata = sdata[-top:]
487 for key, value in sdata:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800488 # Print some nice values if the user didn't
489 # specify an expression to probe
Sasha Goldshtein85384852016-02-12 01:29:39 -0800490 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800491 if not self.probe_type == "r":
Sasha Goldshtein85384852016-02-12 01:29:39 -0800492 key_str = "total calls"
493 else:
494 key_str = "retval = %s" % \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800495 self._v2s(key.v0)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800496 else:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800497 key_str = self._display_key(key)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300498 print("\t%-10s %s" %
Sasha Goldshtein85384852016-02-12 01:29:39 -0800499 (str(value.value), key_str))
500 elif self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800501 label = self.label or (self._display_expr(0)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300502 if not self.is_default_expr else "retval")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800503 data.print_log2_hist(val_type=label)
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300504 if not self.cumulative:
505 data.clear()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800506
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700507 def __str__(self):
508 return self.label or self.raw_spec
509
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800510class Tool(object):
511 examples = """
Sasha Goldshtein85384852016-02-12 01:29:39 -0800512Probe specifier syntax:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700513 {p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800514Where:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300515 p,r,t,u -- probe at function entry, function exit, kernel
516 tracepoint, or USDT probe
Sasha Goldshteine3501152016-02-13 03:56:29 -0800517 in exit probes: can use $retval, $entry(param), $latency
Sasha Goldshtein85384852016-02-12 01:29:39 -0800518 library -- the library that contains the function
519 (leave empty for kernel functions)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800520 category -- the category of the kernel tracepoint (e.g. net, sched)
521 function -- the function name to trace (or tracepoint name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800522 signature -- the function's parameters, as in the C header
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800523 type -- the type of the expression to collect (supports multiple)
524 expr -- the expression to collect (supports multiple)
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800525 filter -- the filter that is applied to collected values
526 label -- the label for this probe in the resulting output
Sasha Goldshtein85384852016-02-12 01:29:39 -0800527
528EXAMPLES:
529
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800530argdist -H 'p::__kmalloc(u64 size):u64:size'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800531 Print a histogram of allocation sizes passed to kmalloc
532
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800533argdist -p 1005 -C 'p:c:malloc(size_t size):size_t:size:size==16'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800534 Print a frequency count of how many times process 1005 called malloc
535 with an allocation size of 16 bytes
536
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800537argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800538 Snoop on all strings returned by gets()
539
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800540argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800541 Print a histogram of nanoseconds per byte from kmalloc allocations
542
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300543argdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800544 Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
545
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800546argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
Sasha Goldshtein85384852016-02-12 01:29:39 -0800547 Print frequency counts of how many times writes were issued to a
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800548 particular file descriptor number, in process 1005, but only show
549 the top 5 busiest fds
Sasha Goldshtein85384852016-02-12 01:29:39 -0800550
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800551argdist -p 1005 -H 'r:c:read()'
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800552 Print a histogram of results (sizes) returned by read() in process 1005
Sasha Goldshtein85384852016-02-12 01:29:39 -0800553
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800554argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800555 Print frequency of reads by process where the latency was >0.1ms
556
muahao852e19b2018-08-22 01:17:36 +0800557argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300558 $entry(count):$latency > 1000000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800559 Print a histogram of read sizes that were longer than 1ms
560
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800561argdist -H \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800562 'p:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800563 Print a histogram of buffer sizes passed to write() across all
564 processes, where the file descriptor was 1 (STDOUT)
565
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800566argdist -C 'p:c:fork()#fork calls'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800567 Count fork() calls in libc across all processes
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800568 Can also use funccount.py, which is easier and more flexible
Sasha Goldshtein85384852016-02-12 01:29:39 -0800569
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300570argdist -H 't:block:block_rq_complete():u32:args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800571 Print histogram of number of sectors in completing block I/O requests
572
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300573argdist -C 't:irq:irq_handler_entry():int:args->irq'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800574 Aggregate interrupts by interrupt request (IRQ)
575
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700576argdist -C 'u:pthread:pthread_start():u64:arg2' -p 1337
577 Print frequency of function addresses used as a pthread start function,
578 relying on the USDT pthread_start probe in process 1337
579
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300580argdist -H 'p:c:sleep(u32 seconds):u32:seconds' \\
581 -H 'p:c:nanosleep(struct timespec *req):long:req->tv_nsec'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800582 Print histograms of sleep() and nanosleep() parameter values
583
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800584argdist -p 2780 -z 120 \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800585 -C 'p:c:write(int fd, char* buf, size_t len):char*:buf:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800586 Spy on writes to STDOUT performed by process 2780, up to a string size
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800587 of 120 characters
Yonghong Songf4470dc2017-12-13 14:12:13 -0800588
589argdist -I 'kernel/sched/sched.h' \\
590 -C 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq):s64:cfs_rq->runtime_remaining'
591 Trace on the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
592 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
593 package. So this command needs to run at the kernel source tree root directory
594 so that the added header file can be found by the compiler.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800595"""
596
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800597 def __init__(self):
598 parser = argparse.ArgumentParser(description="Trace a " +
599 "function and display a summary of its parameter values.",
600 formatter_class=argparse.RawDescriptionHelpFormatter,
601 epilog=Tool.examples)
602 parser.add_argument("-p", "--pid", type=int,
603 help="id of the process to trace (optional)")
604 parser.add_argument("-z", "--string-size", default=80,
605 type=int,
606 help="maximum string size to read from char* arguments")
607 parser.add_argument("-i", "--interval", default=1, type=int,
Akilesh Kailash89967192018-05-18 13:36:54 -0700608 help="output interval, in seconds (default 1 second)")
609 parser.add_argument("-d", "--duration", type=int,
610 help="total duration of trace, in seconds")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800611 parser.add_argument("-n", "--number", type=int, dest="count",
612 help="number of outputs")
613 parser.add_argument("-v", "--verbose", action="store_true",
614 help="print resulting BPF program code before executing")
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300615 parser.add_argument("-c", "--cumulative", action="store_true",
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300616 help="do not clear histograms and freq counts at " +
617 "each interval")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800618 parser.add_argument("-T", "--top", type=int,
619 help="number of top results to show (not applicable to " +
620 "histograms)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300621 parser.add_argument("-H", "--histogram", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800622 dest="histspecifier", metavar="specifier",
623 help="probe specifier to capture histogram of " +
624 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300625 parser.add_argument("-C", "--count", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800626 dest="countspecifier", metavar="specifier",
627 help="probe specifier to capture count of " +
628 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300629 parser.add_argument("-I", "--include", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800630 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300631 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800632 "as either full path, "
633 "or relative to relative to current working directory, "
634 "or relative to default kernel header search path")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800635 self.args = parser.parse_args()
Brendan Gregg4f88a942016-07-22 17:11:51 -0700636 self.usdt_ctx = None
Sasha Goldshtein85384852016-02-12 01:29:39 -0800637
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700638 def _create_probes(self):
639 self.probes = []
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800640 for specifier in (self.args.countspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700641 self.probes.append(Probe(self, "freq", specifier))
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800642 for histspecifier in (self.args.histspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700643 self.probes.append(Probe(self, "hist", histspecifier))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700644 if len(self.probes) == 0:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800645 print("at least one specifier is required")
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500646 exit(1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800647
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800648 def _generate_program(self):
649 bpf_source = """
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800650struct __string_t { char s[%d]; };
651
652#include <uapi/linux/ptrace.h>
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800653 """ % self.args.string_size
654 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300655 if include.startswith((".", "/")):
656 include = os.path.abspath(include)
657 bpf_source += "#include \"%s\"\n" % include
658 else:
659 bpf_source += "#include <%s>\n" % include
660
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700661 bpf_source += BPF.generate_auto_includes(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700662 map(lambda p: p.raw_spec, self.probes))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700663 for probe in self.probes:
664 bpf_source += probe.generate_text()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800665 if self.args.verbose:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300666 for text in [probe.usdt_ctx.get_text()
667 for probe in self.probes
668 if probe.usdt_ctx]:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300669 print(text)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800670 print(bpf_source)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300671 usdt_contexts = [probe.usdt_ctx
672 for probe in self.probes if probe.usdt_ctx]
673 self.bpf = BPF(text=bpf_source, usdt_contexts=usdt_contexts)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800674
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800675 def _attach(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700676 for probe in self.probes:
677 probe.attach(self.bpf)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800678 if self.args.verbose:
yonghong-song6070dcb2018-06-22 14:23:29 -0700679 print("open uprobes: %s" % list(self.bpf.uprobe_fds.keys()))
680 print("open kprobes: %s" % list(self.bpf.kprobe_fds.keys()))
Sasha Goldshtein85384852016-02-12 01:29:39 -0800681
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800682 def _main_loop(self):
683 count_so_far = 0
Akilesh Kailash89967192018-05-18 13:36:54 -0700684 seconds = 0
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800685 while True:
686 try:
687 sleep(self.args.interval)
Akilesh Kailash89967192018-05-18 13:36:54 -0700688 seconds += self.args.interval
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800689 except KeyboardInterrupt:
690 exit()
691 print("[%s]" % strftime("%H:%M:%S"))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700692 for probe in self.probes:
693 probe.display(self.args.top)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800694 count_so_far += 1
695 if self.args.count is not None and \
696 count_so_far >= self.args.count:
697 exit()
Akilesh Kailash89967192018-05-18 13:36:54 -0700698 if self.args.duration and \
699 seconds >= self.args.duration:
700 exit()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800701
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800702 def run(self):
703 try:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700704 self._create_probes()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800705 self._generate_program()
706 self._attach()
707 self._main_loop()
708 except:
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500709 exc_info = sys.exc_info()
710 sys_exit = exc_info[0] is SystemExit
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800711 if self.args.verbose:
712 traceback.print_exc()
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500713 elif not sys_exit:
714 print(exc_info[1])
715 exit(0 if sys_exit else 1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800716
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800717if __name__ == "__main__":
718 Tool().run()