blob: bbf627388bf305bd743f0fb3b7cc02936e11d31f [file] [log] [blame]
Sasha Goldshtein85384852016-02-12 01:29:39 -08001#!/usr/bin/env python
2#
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
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +030012from bcc import BPF, USDT
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
44
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070045 def _generate_entry(self):
46 self.entry_probe_func = self.probe_func_name + "_entry"
47 text = """
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080048int PROBENAME(struct pt_regs *ctx SIGNATURE)
49{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010050 u64 __pid_tgid = bpf_get_current_pid_tgid();
51 u32 __pid = __pid_tgid; // lower 32 bits
52 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080053 PID_FILTER
54 COLLECT
55 return 0;
56}
57"""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080058 text = text.replace("PROBENAME", self.entry_probe_func)
59 text = text.replace("SIGNATURE",
60 "" if len(self.signature) == 0 else ", " + self.signature)
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010061 text = text.replace("PID_FILTER", self._generate_pid_filter())
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080062 collect = ""
63 for pname in self.args_to_probe:
Sasha Goldshteine3501152016-02-13 03:56:29 -080064 param_hash = self.hashname_prefix + pname
65 if pname == "__latency":
66 collect += """
67u64 __time = bpf_ktime_get_ns();
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010068%s.update(&__pid, &__time);
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030069 """ % param_hash
Sasha Goldshteine3501152016-02-13 03:56:29 -080070 else:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010071 collect += "%s.update(&__pid, &%s);\n" % \
Sasha Goldshteine3501152016-02-13 03:56:29 -080072 (param_hash, pname)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080073 text = text.replace("COLLECT", collect)
74 return text
75
76 def _generate_entry_probe(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080077 # Any $entry(name) expressions result in saving that argument
78 # when entering the function.
79 self.args_to_probe = set()
80 regex = r"\$entry\((\w+)\)"
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080081 for expr in self.exprs:
82 for arg in re.finditer(regex, expr):
83 self.args_to_probe.add(arg.group(1))
Sasha Goldshteine3501152016-02-13 03:56:29 -080084 for arg in re.finditer(regex, self.filter):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080085 self.args_to_probe.add(arg.group(1))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080086 if any(map(lambda expr: "$latency" in expr, self.exprs)) or \
87 "$latency" in self.filter:
Sasha Goldshteine3501152016-02-13 03:56:29 -080088 self.args_to_probe.add("__latency")
89 self.param_types["__latency"] = "u64" # nanoseconds
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080090 for pname in self.args_to_probe:
91 if pname not in self.param_types:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030092 raise ValueError("$entry(%s): no such param" %
93 arg)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080094
95 self.hashname_prefix = "%s_param_" % self.probe_hash_name
96 text = ""
97 for pname in self.args_to_probe:
98 # Each argument is stored in a separate hash that is
99 # keyed by pid.
100 text += "BPF_HASH(%s, u32, %s);\n" % \
101 (self.hashname_prefix + pname,
102 self.param_types[pname])
103 text += self._generate_entry()
104 return text
105
106 def _generate_retprobe_prefix(self):
107 # After we're done here, there are __%s_val variables for each
108 # argument we needed to probe using $entry(name), and they all
109 # have values (which isn't necessarily the case if we missed
110 # the method entry probe).
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100111 text = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800112 self.param_val_names = {}
113 for pname in self.args_to_probe:
114 val_name = "__%s_val" % pname
115 text += "%s *%s = %s.lookup(&__pid);\n" % \
116 (self.param_types[pname], val_name,
117 self.hashname_prefix + pname)
118 text += "if (%s == 0) { return 0 ; }\n" % val_name
119 self.param_val_names[pname] = val_name
120 return text
121
122 def _replace_entry_exprs(self):
123 for pname, vname in self.param_val_names.items():
Sasha Goldshteine3501152016-02-13 03:56:29 -0800124 if pname == "__latency":
125 entry_expr = "$latency"
126 val_expr = "(bpf_ktime_get_ns() - *%s)" % vname
127 else:
128 entry_expr = "$entry(%s)" % pname
129 val_expr = "(*%s)" % vname
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800130 for i in range(0, len(self.exprs)):
131 self.exprs[i] = self.exprs[i].replace(
132 entry_expr, val_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800133 self.filter = self.filter.replace(entry_expr,
134 val_expr)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800135
136 def _attach_entry_probe(self):
137 if self.is_user:
138 self.bpf.attach_uprobe(name=self.library,
139 sym=self.function,
140 fn_name=self.entry_probe_func,
141 pid=self.pid or -1)
142 else:
143 self.bpf.attach_kprobe(event=self.function,
144 fn_name=self.entry_probe_func)
145
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800146 def _bail(self, error):
147 raise ValueError("error parsing probe '%s': %s" %
148 (self.raw_spec, error))
149
150 def _validate_specifier(self):
151 # Everything after '#' is the probe label, ignore it
152 spec = self.raw_spec.split('#')[0]
153 parts = spec.strip().split(':')
154 if len(parts) < 3:
155 self._bail("at least the probe type, library, and " +
156 "function signature must be specified")
157 if len(parts) > 6:
158 self._bail("extraneous ':'-separated parts detected")
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700159 if parts[0] not in ["r", "p", "t", "u"]:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300160 self._bail("probe type must be 'p', 'r', 't', or 'u'" +
161 " but got '%s'" % parts[0])
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000162 if re.match(r"\S+\(.*\)", parts[2]) is None:
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800163 self._bail(("function signature '%s' has an invalid " +
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800164 "format") % parts[2])
165
166 def _parse_expr_types(self, expr_types):
167 if len(expr_types) == 0:
168 self._bail("no expr types specified")
169 self.expr_types = expr_types.split(',')
170
171 def _parse_exprs(self, exprs):
172 if len(exprs) == 0:
173 self._bail("no exprs specified")
174 self.exprs = exprs.split(',')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800175
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000176 def _make_valid_identifier(self, ident):
177 return re.sub(r'[^A-Za-z0-9_]', '_', ident)
178
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300179 def __init__(self, tool, type, specifier):
180 self.usdt_ctx = None
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700181 self.streq_functions = ""
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300182 self.pid = tool.args.pid
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300183 self.cumulative = tool.args.cumulative or False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800184 self.raw_spec = specifier
185 self._validate_specifier()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800186
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800187 spec_and_label = specifier.split('#')
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800188 self.label = spec_and_label[1] \
189 if len(spec_and_label) == 2 else None
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800190
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800191 parts = spec_and_label[0].strip().split(':')
Sasha Goldshtein85384852016-02-12 01:29:39 -0800192 self.type = type # hist or freq
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800193 self.probe_type = parts[0]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800194 fparts = parts[2].split('(')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800195 self.function = fparts[0].strip()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800196 if self.probe_type == "t":
197 self.library = "" # kernel
198 self.tp_category = parts[1]
199 self.tp_event = self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700200 elif self.probe_type == "u":
201 self.library = parts[1]
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000202 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100203 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000204 (self.function, Probe.next_probe_index))
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300205 self._enable_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800206 else:
207 self.library = parts[1]
208 self.is_user = len(self.library) > 0
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800209 self.signature = fparts[1].strip()[:-1]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800210 self._parse_signature()
211
212 # If the user didn't specify an expression to probe, we probe
213 # the retval in a ret probe, or simply the value "1" otherwise.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800214 self.is_default_expr = len(parts) < 5
215 if not self.is_default_expr:
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800216 self._parse_expr_types(parts[3])
217 self._parse_exprs(parts[4])
218 if len(self.exprs) != len(self.expr_types):
219 self._bail("mismatched # of exprs and types")
220 if self.type == "hist" and len(self.expr_types) > 1:
221 self._bail("histograms can only have 1 expr")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800222 else:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800223 if not self.probe_type == "r" and self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800224 self._bail("histograms must have expr")
225 self.expr_types = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800226 ["u64" if not self.probe_type == "r" else "int"]
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800227 self.exprs = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800228 ["1" if not self.probe_type == "r" else "$retval"]
Sasha Goldshteine3501152016-02-13 03:56:29 -0800229 self.filter = "" if len(parts) != 6 else parts[5]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800230 self._substitute_exprs()
231
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800232 # Do we need to attach an entry probe so that we can collect an
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800233 # argument that is required for an exit (return) probe?
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800234 def check(expr):
235 keywords = ["$entry", "$latency"]
236 return any(map(lambda kw: kw in expr, keywords))
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800237 self.entry_probe_required = self.probe_type == "r" and \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800238 (any(map(check, self.exprs)) or check(self.filter))
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800239
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000240 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100241 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000242 (self.function, Probe.next_probe_index))
243 self.probe_hash_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100244 "%s_hash%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000245 (self.function, Probe.next_probe_index))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700246 Probe.next_probe_index += 1
247
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300248 def _enable_usdt_probe(self):
249 self.usdt_ctx = USDT(path=self.library, pid=self.pid)
250 self.usdt_ctx.enable_probe(
251 self.function, self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800252
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700253 def _generate_streq_function(self, string):
254 fname = "streq_%d" % Probe.streq_index
255 Probe.streq_index += 1
256 self.streq_functions += """
257static inline bool %s(char const *ignored, char const *str) {
258 char needle[] = %s;
259 char haystack[sizeof(needle)];
260 bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
Sasha Goldshteindcf16752017-01-17 07:40:57 +0000261 for (int i = 0; i < sizeof(needle) - 1; ++i) {
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700262 if (needle[i] != haystack[i]) {
263 return false;
264 }
265 }
266 return true;
267}
268 """ % (fname, string)
269 return fname
270
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800271 def _substitute_exprs(self):
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800272 def repl(expr):
273 expr = self._substitute_aliases(expr)
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700274 matches = re.finditer('STRCMP\\(("[^"]+\\")', expr)
275 for match in matches:
276 string = match.group(1)
277 fname = self._generate_streq_function(string)
278 expr = expr.replace("STRCMP", fname, 1)
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530279 return expr.replace("$retval", "PT_REGS_RC(ctx)")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800280 for i in range(0, len(self.exprs)):
281 self.exprs[i] = repl(self.exprs[i])
282 self.filter = repl(self.filter)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800283
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800284 def _is_string(self, expr_type):
285 return expr_type == "char*" or expr_type == "char *"
Sasha Goldshtein85384852016-02-12 01:29:39 -0800286
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800287 def _generate_hash_field(self, i):
288 if self._is_string(self.expr_types[i]):
289 return "struct __string_t v%d;\n" % i
290 else:
291 return "%s v%d;\n" % (self.expr_types[i], i)
292
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300293 def _generate_usdt_arg_assignment(self, i):
294 expr = self.exprs[i]
295 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000296 arg_index = int(expr[3])
297 arg_ctype = self.usdt_ctx.get_probe_arg_ctype(
298 self.function, arg_index - 1)
299 return (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300300 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000301 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300302 else:
303 return ""
304
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800305 def _generate_field_assignment(self, i):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300306 text = self._generate_usdt_arg_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800307 if self._is_string(self.expr_types[i]):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700308 return (text + " bpf_probe_read(&__key.v%d.s," +
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700309 " sizeof(__key.v%d.s), (void *)%s);\n") % \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800310 (i, i, self.exprs[i])
311 else:
Brendan Gregg4f88a942016-07-22 17:11:51 -0700312 return text + " __key.v%d = %s;\n" % \
313 (i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800314
315 def _generate_hash_decl(self):
316 if self.type == "hist":
317 return "BPF_HISTOGRAM(%s, %s);" % \
318 (self.probe_hash_name, self.expr_types[0])
319 else:
320 text = "struct %s_key_t {\n" % self.probe_hash_name
321 for i in range(0, len(self.expr_types)):
322 text += self._generate_hash_field(i)
323 text += "};\n"
324 text += "BPF_HASH(%s, struct %s_key_t, u64);\n" % \
325 (self.probe_hash_name, self.probe_hash_name)
326 return text
327
328 def _generate_key_assignment(self):
329 if self.type == "hist":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300330 return self._generate_usdt_arg_assignment(0) + \
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300331 ("%s __key = %s;\n" %
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300332 (self.expr_types[0], self.exprs[0]))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800333 else:
334 text = "struct %s_key_t __key = {};\n" % \
335 self.probe_hash_name
336 for i in range(0, len(self.exprs)):
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800337 text += self._generate_field_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800338 return text
339
340 def _generate_hash_update(self):
341 if self.type == "hist":
342 return "%s.increment(bpf_log2l(__key));" % \
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800343 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800344 else:
345 return "%s.increment(__key);" % self.probe_hash_name
346
347 def _generate_pid_filter(self):
348 # Kernel probes need to explicitly filter pid, because the
349 # attach interface doesn't support pid filtering
350 if self.pid is not None and not self.is_user:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100351 return "if (__tgid != %d) { return 0; }" % self.pid
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800352 else:
353 return ""
354
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800355 def generate_text(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800356 program = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700357 probe_text = """
358DATA_DECL
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300359 """ + (
360 "TRACEPOINT_PROBE(%s, %s)" %
361 (self.tp_category, self.tp_event)
362 if self.probe_type == "t"
363 else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700364{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100365 u64 __pid_tgid = bpf_get_current_pid_tgid();
366 u32 __pid = __pid_tgid; // lower 32 bits
367 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700368 PID_FILTER
369 PREFIX
370 if (!(FILTER)) return 0;
371 KEY_EXPR
372 COLLECT
373 return 0;
374}
375"""
376 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700377 signature = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800378
379 # If any entry arguments are probed in a ret probe, we need
380 # to generate an entry probe to collect them
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800381 if self.entry_probe_required:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800382 program += self._generate_entry_probe()
383 prefix += self._generate_retprobe_prefix()
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800384 # Replace $entry(paramname) with a reference to the
385 # value we collected when entering the function:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800386 self._replace_entry_exprs()
387
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300388 if self.probe_type == "p" and len(self.signature) > 0:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700389 # Only entry uprobes/kprobes can have user-specified
390 # signatures. Other probes force it to ().
391 signature = ", " + self.signature
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800392
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300393 program += probe_text.replace("PROBENAME",
394 self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800395 program = program.replace("SIGNATURE", signature)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800396 program = program.replace("PID_FILTER",
397 self._generate_pid_filter())
398
399 decl = self._generate_hash_decl()
400 key_expr = self._generate_key_assignment()
401 collect = self._generate_hash_update()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800402 program = program.replace("DATA_DECL", decl)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800403 program = program.replace("KEY_EXPR", key_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800404 program = program.replace("FILTER",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800405 "1" if len(self.filter) == 0 else self.filter)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800406 program = program.replace("COLLECT", collect)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800407 program = program.replace("PREFIX", prefix)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700408
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700409 return self.streq_functions + program
Sasha Goldshtein85384852016-02-12 01:29:39 -0800410
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700411 def _attach_u(self):
412 libpath = BPF.find_library(self.library)
413 if libpath is None:
Sasha Goldshteinec679712016-10-04 18:33:36 +0300414 libpath = BPF.find_exe(self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700415 if libpath is None or len(libpath) == 0:
Sasha Goldshtein5a1d2e32016-03-30 08:14:44 -0700416 self._bail("unable to find library %s" % self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700417
Brendan Gregg4f88a942016-07-22 17:11:51 -0700418 if self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700419 self.bpf.attach_uretprobe(name=libpath,
420 sym=self.function,
421 fn_name=self.probe_func_name,
422 pid=self.pid or -1)
423 else:
424 self.bpf.attach_uprobe(name=libpath,
425 sym=self.function,
426 fn_name=self.probe_func_name,
427 pid=self.pid or -1)
428
429 def _attach_k(self):
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300430 if self.probe_type == "t":
431 pass # Nothing to do for tracepoints
432 elif self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700433 self.bpf.attach_kretprobe(event=self.function,
434 fn_name=self.probe_func_name)
435 else:
436 self.bpf.attach_kprobe(event=self.function,
437 fn_name=self.probe_func_name)
438
Sasha Goldshtein85384852016-02-12 01:29:39 -0800439 def attach(self, bpf):
440 self.bpf = bpf
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300441 if self.probe_type == "u":
442 return
Sasha Goldshtein85384852016-02-12 01:29:39 -0800443 if self.is_user:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700444 self._attach_u()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800445 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700446 self._attach_k()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800447 if self.entry_probe_required:
448 self._attach_entry_probe()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800449
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800450 def _v2s(self, v):
451 # Most fields can be converted with plain str(), but strings
452 # are wrapped in a __string_t which has an .s field
453 if "__string_t" in type(v).__name__:
454 return str(v.s)
455 return str(v)
456
457 def _display_expr(self, i):
458 # Replace ugly latency calculation with $latency
459 expr = self.exprs[i].replace(
460 "(bpf_ktime_get_ns() - *____latency_val)", "$latency")
461 # Replace alias values back with the alias name
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700462 for alias, subst in Probe.aliases.items():
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800463 expr = expr.replace(subst, alias)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800464 # Replace retval expression with $retval
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530465 expr = expr.replace("PT_REGS_RC(ctx)", "$retval")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800466 # Replace ugly (*__param_val) expressions with param name
467 return re.sub(r"\(\*__(\w+)_val\)", r"\1", expr)
468
469 def _display_key(self, key):
470 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800471 if not self.probe_type == "r":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800472 return "total calls"
473 else:
474 return "retval = %s" % str(key.v0)
475 else:
476 # The key object has v0, ..., vk fields containing
477 # the values of the expressions from self.exprs
478 def str_i(i):
479 key_i = self._v2s(getattr(key, "v%d" % i))
480 return "%s = %s" % \
481 (self._display_expr(i), key_i)
482 return ", ".join(map(str_i, range(0, len(self.exprs))))
483
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800484 def display(self, top):
Sasha Goldshtein85384852016-02-12 01:29:39 -0800485 data = self.bpf.get_table(self.probe_hash_name)
486 if self.type == "freq":
Sasha Goldshteine3501152016-02-13 03:56:29 -0800487 print(self.label or self.raw_spec)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800488 print("\t%-10s %s" % ("COUNT", "EVENT"))
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300489 sdata = sorted(data.items(), key=lambda p: p[1].value)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800490 if top is not None:
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300491 sdata = sdata[-top:]
492 for key, value in sdata:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800493 # Print some nice values if the user didn't
494 # specify an expression to probe
Sasha Goldshtein85384852016-02-12 01:29:39 -0800495 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800496 if not self.probe_type == "r":
Sasha Goldshtein85384852016-02-12 01:29:39 -0800497 key_str = "total calls"
498 else:
499 key_str = "retval = %s" % \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800500 self._v2s(key.v0)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800501 else:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800502 key_str = self._display_key(key)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300503 print("\t%-10s %s" %
Sasha Goldshtein85384852016-02-12 01:29:39 -0800504 (str(value.value), key_str))
505 elif self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800506 label = self.label or (self._display_expr(0)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300507 if not self.is_default_expr else "retval")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800508 data.print_log2_hist(val_type=label)
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300509 if not self.cumulative:
510 data.clear()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800511
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700512 def __str__(self):
513 return self.label or self.raw_spec
514
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800515class Tool(object):
516 examples = """
Sasha Goldshtein85384852016-02-12 01:29:39 -0800517Probe specifier syntax:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700518 {p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800519Where:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300520 p,r,t,u -- probe at function entry, function exit, kernel
521 tracepoint, or USDT probe
Sasha Goldshteine3501152016-02-13 03:56:29 -0800522 in exit probes: can use $retval, $entry(param), $latency
Sasha Goldshtein85384852016-02-12 01:29:39 -0800523 library -- the library that contains the function
524 (leave empty for kernel functions)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800525 category -- the category of the kernel tracepoint (e.g. net, sched)
526 function -- the function name to trace (or tracepoint name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800527 signature -- the function's parameters, as in the C header
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800528 type -- the type of the expression to collect (supports multiple)
529 expr -- the expression to collect (supports multiple)
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800530 filter -- the filter that is applied to collected values
531 label -- the label for this probe in the resulting output
Sasha Goldshtein85384852016-02-12 01:29:39 -0800532
533EXAMPLES:
534
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800535argdist -H 'p::__kmalloc(u64 size):u64:size'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800536 Print a histogram of allocation sizes passed to kmalloc
537
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800538argdist -p 1005 -C 'p:c:malloc(size_t size):size_t:size:size==16'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800539 Print a frequency count of how many times process 1005 called malloc
540 with an allocation size of 16 bytes
541
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800542argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800543 Snoop on all strings returned by gets()
544
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800545argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800546 Print a histogram of nanoseconds per byte from kmalloc allocations
547
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300548argdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800549 Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
550
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800551argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
Sasha Goldshtein85384852016-02-12 01:29:39 -0800552 Print frequency counts of how many times writes were issued to a
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800553 particular file descriptor number, in process 1005, but only show
554 the top 5 busiest fds
Sasha Goldshtein85384852016-02-12 01:29:39 -0800555
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800556argdist -p 1005 -H 'r:c:read()'
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800557 Print a histogram of results (sizes) returned by read() in process 1005
Sasha Goldshtein85384852016-02-12 01:29:39 -0800558
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800559argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800560 Print frequency of reads by process where the latency was >0.1ms
561
muahao852e19b2018-08-22 01:17:36 +0800562argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300563 $entry(count):$latency > 1000000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800564 Print a histogram of read sizes that were longer than 1ms
565
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800566argdist -H \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800567 'p:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800568 Print a histogram of buffer sizes passed to write() across all
569 processes, where the file descriptor was 1 (STDOUT)
570
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800571argdist -C 'p:c:fork()#fork calls'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800572 Count fork() calls in libc across all processes
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800573 Can also use funccount.py, which is easier and more flexible
Sasha Goldshtein85384852016-02-12 01:29:39 -0800574
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300575argdist -H 't:block:block_rq_complete():u32:args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800576 Print histogram of number of sectors in completing block I/O requests
577
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300578argdist -C 't:irq:irq_handler_entry():int:args->irq'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800579 Aggregate interrupts by interrupt request (IRQ)
580
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700581argdist -C 'u:pthread:pthread_start():u64:arg2' -p 1337
582 Print frequency of function addresses used as a pthread start function,
583 relying on the USDT pthread_start probe in process 1337
584
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300585argdist -H 'p:c:sleep(u32 seconds):u32:seconds' \\
586 -H 'p:c:nanosleep(struct timespec *req):long:req->tv_nsec'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800587 Print histograms of sleep() and nanosleep() parameter values
588
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800589argdist -p 2780 -z 120 \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800590 -C 'p:c:write(int fd, char* buf, size_t len):char*:buf:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800591 Spy on writes to STDOUT performed by process 2780, up to a string size
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800592 of 120 characters
Yonghong Songf4470dc2017-12-13 14:12:13 -0800593
594argdist -I 'kernel/sched/sched.h' \\
595 -C 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq):s64:cfs_rq->runtime_remaining'
596 Trace on the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
597 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
598 package. So this command needs to run at the kernel source tree root directory
599 so that the added header file can be found by the compiler.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800600"""
601
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800602 def __init__(self):
603 parser = argparse.ArgumentParser(description="Trace a " +
604 "function and display a summary of its parameter values.",
605 formatter_class=argparse.RawDescriptionHelpFormatter,
606 epilog=Tool.examples)
607 parser.add_argument("-p", "--pid", type=int,
608 help="id of the process to trace (optional)")
609 parser.add_argument("-z", "--string-size", default=80,
610 type=int,
611 help="maximum string size to read from char* arguments")
612 parser.add_argument("-i", "--interval", default=1, type=int,
Akilesh Kailash89967192018-05-18 13:36:54 -0700613 help="output interval, in seconds (default 1 second)")
614 parser.add_argument("-d", "--duration", type=int,
615 help="total duration of trace, in seconds")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800616 parser.add_argument("-n", "--number", type=int, dest="count",
617 help="number of outputs")
618 parser.add_argument("-v", "--verbose", action="store_true",
619 help="print resulting BPF program code before executing")
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300620 parser.add_argument("-c", "--cumulative", action="store_true",
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300621 help="do not clear histograms and freq counts at " +
622 "each interval")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800623 parser.add_argument("-T", "--top", type=int,
624 help="number of top results to show (not applicable to " +
625 "histograms)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300626 parser.add_argument("-H", "--histogram", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800627 dest="histspecifier", metavar="specifier",
628 help="probe specifier to capture histogram of " +
629 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300630 parser.add_argument("-C", "--count", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800631 dest="countspecifier", metavar="specifier",
632 help="probe specifier to capture count of " +
633 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300634 parser.add_argument("-I", "--include", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800635 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300636 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800637 "as either full path, "
638 "or relative to relative to current working directory, "
639 "or relative to default kernel header search path")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800640 self.args = parser.parse_args()
Brendan Gregg4f88a942016-07-22 17:11:51 -0700641 self.usdt_ctx = None
Sasha Goldshtein85384852016-02-12 01:29:39 -0800642
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700643 def _create_probes(self):
644 self.probes = []
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800645 for specifier in (self.args.countspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700646 self.probes.append(Probe(self, "freq", specifier))
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800647 for histspecifier in (self.args.histspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700648 self.probes.append(Probe(self, "hist", histspecifier))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700649 if len(self.probes) == 0:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800650 print("at least one specifier is required")
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500651 exit(1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800652
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800653 def _generate_program(self):
654 bpf_source = """
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800655struct __string_t { char s[%d]; };
656
657#include <uapi/linux/ptrace.h>
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800658 """ % self.args.string_size
659 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300660 if include.startswith((".", "/")):
661 include = os.path.abspath(include)
662 bpf_source += "#include \"%s\"\n" % include
663 else:
664 bpf_source += "#include <%s>\n" % include
665
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700666 bpf_source += BPF.generate_auto_includes(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700667 map(lambda p: p.raw_spec, self.probes))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700668 for probe in self.probes:
669 bpf_source += probe.generate_text()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800670 if self.args.verbose:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300671 for text in [probe.usdt_ctx.get_text()
672 for probe in self.probes
673 if probe.usdt_ctx]:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300674 print(text)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800675 print(bpf_source)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300676 usdt_contexts = [probe.usdt_ctx
677 for probe in self.probes if probe.usdt_ctx]
678 self.bpf = BPF(text=bpf_source, usdt_contexts=usdt_contexts)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800679
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800680 def _attach(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700681 for probe in self.probes:
682 probe.attach(self.bpf)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800683 if self.args.verbose:
yonghong-song6070dcb2018-06-22 14:23:29 -0700684 print("open uprobes: %s" % list(self.bpf.uprobe_fds.keys()))
685 print("open kprobes: %s" % list(self.bpf.kprobe_fds.keys()))
Sasha Goldshtein85384852016-02-12 01:29:39 -0800686
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800687 def _main_loop(self):
688 count_so_far = 0
Akilesh Kailash89967192018-05-18 13:36:54 -0700689 seconds = 0
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800690 while True:
691 try:
692 sleep(self.args.interval)
Akilesh Kailash89967192018-05-18 13:36:54 -0700693 seconds += self.args.interval
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800694 except KeyboardInterrupt:
695 exit()
696 print("[%s]" % strftime("%H:%M:%S"))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700697 for probe in self.probes:
698 probe.display(self.args.top)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800699 count_so_far += 1
700 if self.args.count is not None and \
701 count_so_far >= self.args.count:
702 exit()
Akilesh Kailash89967192018-05-18 13:36:54 -0700703 if self.args.duration and \
704 seconds >= self.args.duration:
705 exit()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800706
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800707 def run(self):
708 try:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700709 self._create_probes()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800710 self._generate_program()
711 self._attach()
712 self._main_loop()
713 except:
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500714 exc_info = sys.exc_info()
715 sys_exit = exc_info[0] is SystemExit
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800716 if self.args.verbose:
717 traceback.print_exc()
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500718 elif not sys_exit:
719 print(exc_info[1])
720 exit(0 if sys_exit else 1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800721
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800722if __name__ == "__main__":
723 Tool().run()