xref: /aosp_15_r20/external/bcc/tests/python/test_tools_smoke.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/env python3
2# Copyright (c) Sasha Goldshtein, 2017
3# Licensed under the Apache License, Version 2.0 (the "License")
4
5import subprocess
6import os
7import re
8from unittest import main, skipUnless, TestCase
9from utils import mayFail, kernel_version_ge
10
11TOOLS_DIR = "/bcc/tools/"
12
13def _helpful_rc_msg(rc, allow_early, kill):
14    s = "rc was %d\n" % rc
15    if rc == 0:
16        s += "\tMeaning: command returned successfully before test timeout\n"
17    elif rc == 124:
18        s += "\tMeaning: command was killed by INT signal\n"
19    elif rc == 137:
20        s += "\tMeaning: command was killed by KILL signal\n"
21
22    s += "Command was expected to do one of:\n"
23    s += "\tBe killed by SIGINT\n"
24    if kill:
25        s += "\tBe killed by SIGKILL\n"
26    if allow_early:
27        s += "\tSuccessfully return before being killed\n"
28
29    return s
30
31@skipUnless(kernel_version_ge(4,1), "requires kernel >= 4.1")
32class SmokeTests(TestCase):
33    # Use this for commands that have a built-in timeout, so they only need
34    # to be killed in case of a hard hang.
35    def run_with_duration(self, command, timeout=10):
36        full_command = TOOLS_DIR + command
37        self.assertEqual(0,     # clean exit
38                subprocess.call("timeout -s KILL %ds %s > /dev/null" %
39                                (timeout, full_command), shell=True))
40
41    # Use this for commands that don't have a built-in timeout, so we have
42    # to Ctrl-C out of them by sending SIGINT. If that still doesn't stop
43    # them, send a kill signal 5 seconds later.
44    def run_with_int(self, command, timeout=5, kill_timeout=5,
45                     allow_early=False, kill=False):
46        full_command = TOOLS_DIR + command
47        signal = "KILL" if kill else "INT"
48        rc = subprocess.call("timeout -s %s -k %ds %ds %s > /dev/null" %
49                (signal, kill_timeout, timeout, full_command), shell=True)
50        # timeout returns 124 if the program did not terminate prematurely,
51        # and returns 137 if we used KILL instead of INT. So there are three
52        # sensible scenarios:
53        #   1. The script is allowed to return early, and it did, with a
54        #      success return code.
55        #   2. The script timed out and was killed by the SIGINT signal.
56        #   3. The script timed out and was killed by the SIGKILL signal, and
57        #      this was what we asked for using kill=True.
58        self.assertTrue((rc == 0 and allow_early) or rc == 124
59                        or (rc == 137 and kill), _helpful_rc_msg(rc,
60                        allow_early, kill))
61
62    def kmod_loaded(self, mod):
63        with open("/proc/modules", "r") as mods:
64            reg = re.compile("^%s\s" % mod)
65            for line in mods:
66                if reg.match(line):
67                    return 1
68                return 0
69
70    def setUp(self):
71        pass
72
73    def tearDown(self):
74        pass
75
76    @mayFail("This fails on github actions environment, and needs to be fixed")
77    def test_argdist(self):
78        self.run_with_duration("argdist.py -v -C 'p::do_sys_open()' -n 1 -i 1")
79
80    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
81    def test_bashreadline(self):
82        self.run_with_int("bashreadline.py")
83
84    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
85    def test_bindsnoop(self):
86        self.run_with_int("bindsnoop.py")
87
88    def test_biolatency(self):
89        self.run_with_duration("biolatency.py 1 1")
90
91    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
92    def test_biosnoop(self):
93        self.run_with_int("biosnoop.py")
94
95    def test_biotop(self):
96        self.run_with_duration("biotop.py 1 1")
97
98    def test_bitesize(self):
99        self.run_with_int("biotop.py")
100
101    def test_bpflist(self):
102        self.run_with_duration("bpflist.py")
103
104    def test_btrfsdist(self):
105        # Will attempt to do anything meaningful only when btrfs is installed.
106        self.run_with_duration("btrfsdist.py 1 1")
107
108    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
109    def test_btrfsslower(self):
110        # Will attempt to do anything meaningful only when btrfs is installed.
111        self.run_with_int("btrfsslower.py", allow_early=True)
112
113    def test_cachestat(self):
114        self.run_with_duration("cachestat.py 1 1")
115
116    def test_cachetop(self):
117        # TODO cachetop doesn't like to run without a terminal, disabled
118        # for now.
119        # self.run_with_int("cachetop.py 1")
120        pass
121
122    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
123    def test_capable(self):
124        self.run_with_int("capable.py")
125
126    def test_cpudist(self):
127        self.run_with_duration("cpudist.py 1 1")
128
129    @skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
130    def test_cpuunclaimed(self):
131        self.run_with_duration("cpuunclaimed.py 1 1")
132
133    @skipUnless(kernel_version_ge(4,17), "requires kernel >= 4.17")
134    def test_compactsnoop(self):
135        self.run_with_int("compactsnoop.py")
136
137    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
138    def test_dbslower(self):
139        # Deliberately left empty -- dbslower requires an instance of either
140        # MySQL or PostgreSQL to be running, or it fails to attach.
141        pass
142
143    @skipUnless(kernel_version_ge(4,3), "requires kernel >= 4.3")
144    def test_dbstat(self):
145        # Deliberately left empty -- dbstat requires an instance of either
146        # MySQL or PostgreSQL to be running, or it fails to attach.
147        pass
148
149    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
150    def test_dcsnoop(self):
151        self.run_with_int("dcsnoop.py")
152
153    def test_dcstat(self):
154        self.run_with_duration("dcstat.py 1 1")
155
156    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
157    def test_deadlock(self):
158        # TODO This tool requires a massive BPF stack traces table allocation,
159        # which might fail the run or even trigger the oomkiller to kill some
160        # other processes. Disabling for now.
161        # self.run_with_int("deadlock.py $(pgrep -n bash)", timeout=10)
162        pass
163
164    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
165    def test_drsnoop(self):
166        self.run_with_int("drsnoop.py")
167
168    @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
169    def test_execsnoop(self):
170        self.run_with_int("execsnoop.py")
171
172    def test_ext4dist(self):
173        self.run_with_duration("ext4dist.py 1 1")
174
175    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
176    def test_ext4slower(self):
177        self.run_with_int("ext4slower.py")
178
179    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
180    def test_filelife(self):
181        self.run_with_int("filelife.py")
182
183    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
184    def test_fileslower(self):
185        self.run_with_int("fileslower.py")
186
187    def test_filetop(self):
188        self.run_with_duration("filetop.py 1 1")
189
190    def test_funccount(self):
191        self.run_with_int("funccount.py __kmalloc -i 1")
192
193    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
194    def test_funclatency(self):
195        self.run_with_int("funclatency.py __kmalloc -i 1")
196
197    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
198    def test_funcslower(self):
199        self.run_with_int("funcslower.py __kmalloc")
200
201    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
202    def test_gethostlatency(self):
203        self.run_with_int("gethostlatency.py")
204
205    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
206    def test_hardirqs(self):
207        self.run_with_duration("hardirqs.py 1 1")
208
209    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
210    def test_killsnoop(self):
211        # Because killsnoop intercepts signals, if we send it a SIGINT we we
212        # we likely catch it while it is handling the data packet from the
213        # BPF program, and the exception from the SIGINT will be swallowed by
214        # ctypes. Therefore, we use SIGKILL.
215        # To reproduce the above issue, run killsnoop and in another shell run
216        # `kill -s SIGINT $(pidof python)`. As a result, killsnoop will print
217        # a traceback but will not exit.
218        self.run_with_int("killsnoop.py", kill=True)
219
220    @skipUnless(kernel_version_ge(4,18), "requires kernel >= 4.18")
221    def test_klockstat(self):
222        self.run_with_int("klockstat.py")
223
224    @skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
225    def test_llcstat(self):
226        # Requires PMU, which is not available in virtual machines.
227        pass
228
229    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
230    def test_mdflush(self):
231        self.run_with_int("mdflush.py")
232
233    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
234    def test_memleak(self):
235        self.run_with_duration("memleak.py 1 1")
236
237    @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
238    def test_mountsnoop(self):
239        self.run_with_int("mountsnoop.py")
240
241    @skipUnless(kernel_version_ge(4,3), "requires kernel >= 4.3")
242    def test_mysqld_qslower(self):
243        # Deliberately left empty -- mysqld_qslower requires an instance of
244        # MySQL to be running, or it fails to attach.
245        pass
246
247    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
248    def test_nfsslower(self):
249        if(self.kmod_loaded("nfs")):
250            self.run_with_int("nfsslower.py")
251        else:
252            pass
253
254    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
255    def test_nfsdist(self):
256        if(self.kmod_loaded("nfs")):
257            self.run_with_duration("nfsdist.py 1 1")
258        else:
259            pass
260
261    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
262    @mayFail("This fails on github actions environment, and needs to be fixed")
263    def test_offcputime(self):
264        self.run_with_duration("offcputime.py 1")
265
266    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
267    def test_offwaketime(self):
268        self.run_with_duration("offwaketime.py 1")
269
270    @skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
271    def test_oomkill(self):
272        self.run_with_int("oomkill.py")
273
274    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
275    def test_opensnoop(self):
276        self.run_with_int("opensnoop.py")
277
278    def test_pidpersec(self):
279        self.run_with_int("pidpersec.py")
280
281    @skipUnless(kernel_version_ge(4,17), "requires kernel >= 4.17")
282    @mayFail("This fails on github actions environment, and needs to be fixed")
283    def test_syscount(self):
284        self.run_with_int("ppchcalls.py -i 1")
285
286    @skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
287    def test_profile(self):
288        self.run_with_duration("profile.py 1")
289
290    def test_runqlat(self):
291        self.run_with_duration("runqlat.py 1 1")
292
293    @skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
294    def test_runqlen(self):
295        self.run_with_duration("runqlen.py 1 1")
296
297    @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
298    def test_shmsnoop(self):
299        self.run_with_int("shmsnoop.py")
300
301    @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
302    def test_sofdsnoop(self):
303        self.run_with_int("sofdsnoop.py")
304
305    def test_slabratetop(self):
306        self.run_with_duration("slabratetop.py 1 1")
307
308    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
309    def test_softirqs(self):
310        self.run_with_duration("softirqs.py 1 1")
311        pass
312
313    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
314    def test_solisten(self):
315        self.run_with_int("solisten.py")
316
317    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
318    @mayFail("This fails on github actions environment, and needs to be fixed")
319    def test_sslsniff(self):
320        self.run_with_int("sslsniff.py")
321
322    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
323    def test_stackcount(self):
324        self.run_with_int("stackcount.py __kmalloc -i 1")
325
326    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
327    def test_statsnoop(self):
328        self.run_with_int("statsnoop.py")
329
330    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
331    def test_syncsnoop(self):
332        self.run_with_int("syncsnoop.py")
333
334    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
335    def test_syscount(self):
336        self.run_with_int("syscount.py -i 1")
337
338    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
339    def test_tcpaccept(self):
340        self.run_with_int("tcpaccept.py")
341
342    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
343    def test_tcpconnect(self):
344        self.run_with_int("tcpconnect.py")
345
346    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
347    def test_tcpconnlat(self):
348        self.run_with_int("tcpconnlat.py")
349
350    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
351    def test_tcplife(self):
352        self.run_with_int("tcplife.py")
353
354    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
355    def test_tcpretrans(self):
356        self.run_with_int("tcpretrans.py")
357
358    @skipUnless(kernel_version_ge(4, 7), "requires kernel >= 4.7")
359    @mayFail("This fails on github actions environment, and needs to be fixed")
360    def test_tcpdrop(self):
361        self.run_with_int("tcpdrop.py")
362
363    def test_tcptop(self):
364        self.run_with_duration("tcptop.py 1 1")
365
366    def test_tcpcong(self):
367        self.run_with_duration("tcpcong.py 1 1")
368
369    def test_tplist(self):
370        self.run_with_duration("tplist.py -p %d" % os.getpid())
371
372    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
373    def test_trace(self):
374        self.run_with_int("trace.py do_sys_open")
375
376    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
377    @mayFail("This fails on github actions environment, and needs to be fixed")
378    def test_ttysnoop(self):
379        self.run_with_int("ttysnoop.py /dev/console")
380
381    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
382    def test_ucalls(self):
383        self.run_with_int("lib/ucalls.py -l none -S %d" % os.getpid())
384
385    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
386    def test_uflow(self):
387        # The Python installed on the Ubuntu buildbot doesn't have USDT
388        # probes, so we can't run uflow.
389        # self.run_with_int("pythonflow.py %d" % os.getpid())
390        pass
391
392    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
393    def test_ugc(self):
394        # This requires a runtime that has GC probes to be installed.
395        # Python has them, but only in very recent versions. Skip.
396        pass
397
398    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
399    def test_uobjnew(self):
400        self.run_with_int("cobjnew.sh %d" % os.getpid())
401
402    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
403    def test_ustat(self):
404        self.run_with_duration("lib/ustat.py 1 1")
405
406    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
407    def test_uthreads(self):
408        self.run_with_int("lib/uthreads.py %d" % os.getpid())
409
410    def test_vfscount(self):
411        self.run_with_int("vfscount.py", timeout=15, kill_timeout=15)
412
413    def test_vfsstat(self):
414        self.run_with_duration("vfsstat.py 1 1")
415
416    @skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
417    def test_wakeuptime(self):
418        self.run_with_duration("wakeuptime.py 1")
419
420    def test_xfsdist(self):
421        # Doesn't work on build bot because xfs functions not present in the
422        # kernel image.
423        # self.run_with_duration("xfsdist.py 1 1")
424        pass
425
426    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
427    def test_xfsslower(self):
428        # Doesn't work on build bot because xfs functions not present in the
429        # kernel image.
430        # self.run_with_int("xfsslower.py")
431        pass
432
433    def test_zfsdist(self):
434        # Fails to attach the probe if zfs is not installed.
435        pass
436
437    @skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
438    def test_zfsslower(self):
439        # Fails to attach the probe if zfs is not installed.
440        pass
441
442if __name__ == "__main__":
443    main()
444