From c163ba2ee8fa64a213232eed5482463eafab66ab Mon Sep 17 00:00:00 2001 From: Antoine Busque Date: Fri, 19 Feb 2016 16:27:45 -0500 Subject: [PATCH] Tests: refactor test framework to eliminate py.test This replaces the external py.test dependency with the standard `unittest` package. Signed-off-by: Antoine Busque --- setup.cfg | 3 - setup.py | 3 +- tests/__init__.py | 21 +++ tests/analysis_test.py | 62 ++++++++ tests/expected/cputop.txt | 15 ++ tests/expected/iolatencytop.txt | 14 ++ tests/expected/iousagetop.txt | 54 +++++++ tests/expected/irqlog.txt | 19 +++ tests/expected/irqstats.txt | 13 ++ tests/test_cputop.py | 81 ++++++----- tests/test_io.py | 153 +++++++------------- tests/test_irq.py | 180 +++++++++++------------- tests/{TraceTest.py => trace_writer.py} | 74 ++++------ 13 files changed, 394 insertions(+), 298 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/analysis_test.py create mode 100644 tests/expected/cputop.txt create mode 100644 tests/expected/iolatencytop.txt create mode 100644 tests/expected/iousagetop.txt create mode 100644 tests/expected/irqlog.txt create mode 100644 tests/expected/irqstats.txt rename tests/{TraceTest.py => trace_writer.py} (94%) diff --git a/setup.cfg b/setup.cfg index ef2a91b..7666855 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,6 +5,3 @@ versionfile_source = lttnganalyses/_version.py versionfile_build = lttnganalyses/_version.py tag_prefix = v parentdir_prefix = lttnganalyses- - -[aliases] -test=pytest diff --git a/setup.py b/setup.py index 1186f5f..8b90cd4 100755 --- a/setup.py +++ b/setup.py @@ -129,6 +129,5 @@ setup( 'progressbar': ["progressbar"] }, - setup_requires=['pytest-runner'], - tests_require=['pytest'] + test_suite='tests', ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..8eca6e0 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,21 @@ +# The MIT License (MIT) +# +# Copyright (C) 2016 - Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/tests/analysis_test.py b/tests/analysis_test.py new file mode 100644 index 0000000..a9a7263 --- /dev/null +++ b/tests/analysis_test.py @@ -0,0 +1,62 @@ +# The MIT License (MIT) +# +# Copyright (C) 2016 - Julien Desfossez +# Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import subprocess +import unittest +from .trace_writer import TraceWriter + + +class AnalysisTest(unittest.TestCase): + COMMON_OPTIONS = '--no-progress --skip-validation' + + def set_up_class(self): + dirname = os.path.dirname(os.path.realpath(__file__)) + self.data_path = dirname + '/expected/' + self.maxDiff = None + self.trace_writer = TraceWriter() + self.write_trace() + + def tear_down_class(self): + self.trace_writer.rm_trace() + + def write_trace(self): + raise NotImplementedError + + def run(self, result=None): + self.set_up_class() + super().run(result) + self.tear_down_class() + + return result + + def get_expected_output(self, filename): + with open(self.data_path + filename, 'r') as expected_file: + return expected_file.read() + + def get_cmd_output(self, exec_name, options=''): + cmd_fmt = './{} {} {} {}' + cmd = cmd_fmt.format(exec_name, self.COMMON_OPTIONS, + options, self.trace_writer.trace_root) + + return subprocess.getoutput(cmd) diff --git a/tests/expected/cputop.txt b/tests/expected/cputop.txt new file mode 100644 index 0000000..d249086 --- /dev/null +++ b/tests/expected/cputop.txt @@ -0,0 +1,15 @@ +Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:11.000000000] +Per-TID Usage Process Migrations Priorities +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 100.00 % prog100pc-cpu5 (42) 0 [20] +████████████████████ 25.00 % prog25pc-cpu1 (30665) 0 [20] +████████████████ 20.00 % prog20pc-cpu0 (30664) 0 [20] + +Per-CPU Usage +################################################################################ +████████████████ 20.00 % CPU 0 +████████████████████ 25.00 % CPU 1 +████████████████████████████████████████████████████████████████████████████████ 100.00 % CPU 5 + + +Total CPU Usage: 48.33% diff --git a/tests/expected/iolatencytop.txt b/tests/expected/iolatencytop.txt new file mode 100644 index 0000000..3941470 --- /dev/null +++ b/tests/expected/iolatencytop.txt @@ -0,0 +1,14 @@ +Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.024000000] + +Top system call latencies open (usec) +Begin End Name Duration (usec) Size Proc PID Filename +[19:00:01.023000000,19:00:01.024000000] open 1000.000 N/A app3 101 test/open/file (fd=42) + +Top system call latencies read (usec) +Begin End Name Duration (usec) Size Proc PID Filename +[19:00:01.008000000,19:00:01.009000000] read 1000.000 100 B app2 100 testfile (fd=3) +[19:00:01.012000000,19:00:01.013000000] read 1000.000 42 B app3 101 unknown (fd=3) + +Top system call latencies write (usec) +Begin End Name Duration (usec) Size Proc PID Filename +[19:00:01.004000000,19:00:01.005000000] write 1000.000 10 B app 99 unknown (fd=4) \ No newline at end of file diff --git a/tests/expected/iousagetop.txt b/tests/expected/iousagetop.txt new file mode 100644 index 0000000..e62ce85 --- /dev/null +++ b/tests/expected/iousagetop.txt @@ -0,0 +1,54 @@ +Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.024000000] +Per-process I/O Read Process Disk Net Unknown +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 100 B app2 (100) 0 B 0 B 100 B +█████████████████████████████████ 42 B app3 (unknown (tid=101)) 0 B 0 B 42 B + 0 B app (99) 0 B 0 B 0 B + +Per-process I/O Write Process Disk Net Unknown +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 10 B app (99) 0 B 0 B 10 B + 0 B app2 (100) 0 B 0 B 0 B + 0 B app3 (unknown (tid=101)) 0 B 0 B 0 B + +Per-file I/O Read Path +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 100 B testfile +█████████████████████████████████ 42 B unknown (app3) + +Per-file I/O Write Path +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 10 B unknown (app) + +Block I/O Read Process +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 5.00 KiB app (pid=99) + +Block I/O Write Process +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 10.00 KiB app3 (pid=unknown (tid=101)) + +Disk Requests Sector Count Disk +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 20 sectors (8,0) +████████████████████████████████████████ 10 sectors (252,0) + +Disk Request Count Disk +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 1 requests (252,0) +████████████████████████████████████████████████████████████████████████████████ 1 requests (8,0) + +Disk Request Average Latency Disk +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 1.00 ms (252,0) +████████████████████████████████████████████████████████████████████████████████ 1.00 ms (8,0) + +Network Received Bytes Interface +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 200 B wlan0 +████████████████████████████████████████ 100 B wlan1 + +Network Sent Bytes Interface +################################################################################ +████████████████████████████████████████████████████████████████████████████████ 100 B wlan0 + 0 B wlan1 diff --git a/tests/expected/irqlog.txt b/tests/expected/irqlog.txt new file mode 100644 index 0000000..a8b041e --- /dev/null +++ b/tests/expected/irqlog.txt @@ -0,0 +1,19 @@ +Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.045000000] +Begin End Duration (us) CPU Type # Name +[19:00:01.007000000, 19:00:01.008000000] 1000.000 1 SoftIRQ 1 TIMER_SOFTIRQ (raised at 19:00:01.000000000) +[19:00:01.006000000, 19:00:01.009000000] 3000.000 3 SoftIRQ 1 TIMER_SOFTIRQ (raised at 19:00:01.001000000) +[19:00:01.010000000, 19:00:01.012000000] 2000.000 1 SoftIRQ 9 RCU_SOFTIRQ (raised at 19:00:01.002000000) +[19:00:01.011000000, 19:00:01.013000000] 2000.000 3 SoftIRQ 7 SCHED_SOFTIRQ (raised at 19:00:01.005000000) +[19:00:01.014000000, 19:00:01.015000000] 1000.000 3 SoftIRQ 9 RCU_SOFTIRQ (raised at 19:00:01.004000000) +[19:00:01.016000000, 19:00:01.018000000] 2000.000 0 IRQ 41 ahci +[19:00:01.019000000, 19:00:01.020000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.017000000) +[19:00:01.021000000, 19:00:01.023000000] 2000.000 0 IRQ 41 ahci +[19:00:01.024000000, 19:00:01.025000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.022000000) +[19:00:01.026000000, 19:00:01.028000000] 2000.000 0 IRQ 41 ahci +[19:00:01.029000000, 19:00:01.030000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.027000000) +[19:00:01.031000000, 19:00:01.033000000] 2000.000 0 IRQ 41 ahci +[19:00:01.034000000, 19:00:01.035000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.032000000) +[19:00:01.036000000, 19:00:01.038000000] 2000.000 0 IRQ 41 ahci +[19:00:01.039000000, 19:00:01.040000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.037000000) +[19:00:01.041000000, 19:00:01.043000000] 2000.000 0 IRQ 41 ahci +[19:00:01.044000000, 19:00:01.045000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.042000000) \ No newline at end of file diff --git a/tests/expected/irqstats.txt b/tests/expected/irqstats.txt new file mode 100644 index 0000000..a5d2807 --- /dev/null +++ b/tests/expected/irqstats.txt @@ -0,0 +1,13 @@ +Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.045000000] +Hard IRQ Duration (us) + count min avg max stdev +----------------------------------------------------------------------------------| +41: 6 2000.000 2000.000 2000.000 0.000 | + +Soft IRQ Duration (us) Raise latency (us) + count min avg max stdev | count min avg max stdev +----------------------------------------------------------------------------------|------------------------------------------------------------ +1: 2 1000.000 2000.000 3000.000 1414.214 | 2 5000.000 6000.000 7000.000 1414.214 +4: 6 1000.000 1000.000 1000.000 0.000 | 6 2000.000 2000.000 2000.000 0.000 +7: 1 2000.000 2000.000 2000.000 ? | 1 6000.000 6000.000 6000.000 ? +9: 2 1000.000 1500.000 2000.000 707.107 | 2 8000.000 9000.000 10000.000 1414.214 \ No newline at end of file diff --git a/tests/test_cputop.py b/tests/test_cputop.py index 5e767e2..77256ce 100644 --- a/tests/test_cputop.py +++ b/tests/test_cputop.py @@ -1,48 +1,47 @@ -from TraceTest import AnalysesTest -import sys - - -class CpuTest(AnalysesTest): - def __init__(self, delete_trace=True, verbose=False): - super().__init__(delete_trace=delete_trace, - verbose=verbose) - self.test_list = [('cputop', self.run_no_option)] - +# The MIT License (MIT) +# +# Copyright (C) 2016 - Julien Desfossez +# Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from .analysis_test import AnalysisTest + + +class CpuTest(AnalysisTest): def write_trace(self): # runs the whole time: 100% - self.t.write_sched_switch(1000, 5, "swapper/5", 0, "prog100pc-cpu5", 42) + self.trace_writer.write_sched_switch(1000, 5, 'swapper/5', + 0, 'prog100pc-cpu5', 42) # runs for 2s alternating with swapper out every 100ms - self.t.sched_switch_50pc(1100, 5000, 0, 100, - "swapper/0", 0, "prog20pc-cpu0", 30664) + self.trace_writer.sched_switch_50pc(1100, 5000, 0, 100, 'swapper/0', + 0, 'prog20pc-cpu0', 30664) # runs for 2.5s alternating with swapper out every 100ms - self.t.sched_switch_50pc(5100, 10000, 1, 100, - "swapper/1", 0, "prog25pc-cpu1", 30665) + self.trace_writer.sched_switch_50pc(5100, 10000, 1, 100, 'swapper/1', + 0, 'prog25pc-cpu1', 30665) # switch out prog100pc-cpu5 - self.t.write_sched_switch(11000, 5, "prog100pc-cpu5", 42, "swapper/5", 0) - self.t.flush() - - def run_no_option(self): - expected = """Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:11.000000000] -Per-TID CPU Usage -############################################################################### -██████████████████████████████████████████████████ 100.00 % prog100pc-cpu5 (42) (prio: 20) -████████████ 25.00 % prog25pc-cpu1 (30665) (prio: 20) -██████████ 20.00 % prog20pc-cpu0 (30664) (prio: 20) -Per-CPU Usage -############################################################################### -█████████████ 20.00 % CPU 0 -████████████████ 25.00 % CPU 1 -█████████████████████████████████████████████████████████████████ 100.00 % CPU 5 - -Total CPU Usage: 48.33% -""" - - return self.compare_output('%slttng-cputop %s "%s"' % ( - self.cmd_root, self.common_options, self.t.trace_root), - expected) + self.trace_writer.write_sched_switch(11000, 5, 'prog100pc-cpu5', + 42, 'swapper/5', 0) + self.trace_writer.flush() + def test_cputop(self): + expected = self.get_expected_output('cputop.txt') + result = self.get_cmd_output('lttng-cputop') -def test_answer(): - t = CpuTest(verbose=True) - ok = t.run() - assert(ok) + self.assertMultiLineEqual(result, expected) diff --git a/tests/test_io.py b/tests/test_io.py index 3706170..9eb0e56 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -1,122 +1,71 @@ -from TraceTest import AnalysesTest -import sys +# The MIT License (MIT) +# +# Copyright (C) 2016 - Julien Desfossez +# Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +from .analysis_test import AnalysisTest -class IoTest(AnalysesTest): - def __init__(self, delete_trace=False, verbose=False): - super().__init__(delete_trace=delete_trace, - verbose=verbose) - self.test_list = [('iousagetop', self.run_iousagetop), - ('iolatencytop', self.run_iolatencytop)] +class IoTest(AnalysisTest): def write_trace(self): # app (99) is known at statedump - self.t.write_lttng_statedump_process_state(1000, 0, 99, 99, 99, 99, 98, - 98, "app", 0, 5, 0, 5, 0) + self.trace_writer.write_lttng_statedump_process_state( + 1000, 0, 99, 99, 99, 99, 98, 98, 'app', 0, 5, 0, 5, 0) # app2 (100) unknown at statedump has testfile, FD 3 defined at # statedump - self.t.write_lttng_statedump_file_descriptor(1001, 0, 100, 3, 0, 0, - "testfile") + self.trace_writer.write_lttng_statedump_file_descriptor( + 1001, 0, 100, 3, 0, 0, 'testfile') # app write 10 bytes to FD 4 - self.t.write_sched_switch(1002, 0, "swapper/0", 0, "app", 99) - self.t.write_syscall_write(1004, 0, 1, 4, 0xabcd, 10, 10) + self.trace_writer.write_sched_switch(1002, 0, 'swapper/0', 0, 'app', 99) + self.trace_writer.write_syscall_write(1004, 0, 1, 4, 0xabcd, 10, 10) # app2 reads 100 bytes in FD 3 - self.t.write_sched_switch(1006, 0, "app", 99, "app2", 100) - self.t.write_syscall_read(1008, 0, 1, 3, 0xcafe, 100, 100) + self.trace_writer.write_sched_switch(1006, 0, 'app', 99, 'app2', 100) + self.trace_writer.write_syscall_read(1008, 0, 1, 3, 0xcafe, 100, 100) # app3 and its FD 3 are completely unknown at statedump, tries to read 100 # bytes from FD 3 but only gets 42 - self.t.write_sched_switch(1010, 0, "app2", 100, "app3", 101) - self.t.write_syscall_read(1012, 0, 1, 3, 0xcafe, 100, 42) + self.trace_writer.write_sched_switch(1010, 0, 'app2', 100, 'app3', 101) + self.trace_writer.write_syscall_read(1012, 0, 1, 3, 0xcafe, 100, 42) # block write - self.t.write_block_rq_issue(1015, 0, 264241152, 33, 10, 40, 99, 0, 0, "", "app") - self.t.write_block_rq_complete(1016, 0, 264241152, 33, 10, 0, 0, 0, "") + self.trace_writer.write_block_rq_issue(1015, 0, 264241152, 33, 10, 40, 99, 0, 0, '', 'app') + self.trace_writer.write_block_rq_complete(1016, 0, 264241152, 33, 10, 0, 0, 0, '') # block read - # FIXME: does not look right - self.t.write_block_rq_issue(1017, 0, 8388608, 33, 11, 90, 101, 1, 0, "", "app3") - self.t.write_block_rq_complete(1018, 0, 8388608, 33, 11, 0, 1, 0, "") + self.trace_writer.write_block_rq_issue(1017, 0, 8388608, 33, 20, 90, 101, 1, 0, '', 'app3') + self.trace_writer.write_block_rq_complete(1018, 0, 8388608, 33, 20, 0, 1, 0, '') # net xmit - # FIXME: does not look right - self.t.write_net_dev_xmit(1020, 2, 0xff, 32, 0, "wlan0") + self.trace_writer.write_net_dev_xmit(1020, 2, 0xff, 32, 100, 'wlan0') # net receive - self.t.write_netif_receive_skb(1021, 1, 0xff, 100, "wlan1") - self.t.write_netif_receive_skb(1022, 1, 0xff, 200, "wlan0") + self.trace_writer.write_netif_receive_skb(1021, 1, 0xff, 100, 'wlan1') + self.trace_writer.write_netif_receive_skb(1022, 1, 0xff, 200, 'wlan0') # syscall open - self.t.write_syscall_open(1023, 0, 1, "test/open/file", 0, 0, 42) - self.t.flush() + self.trace_writer.write_syscall_open(1023, 0, 1, 'test/open/file', 0, 0, 42) + self.trace_writer.flush() - def run_iousagetop(self): - expected = """Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.022000000] -Per-process I/O Read -############################################################################### -██████████████████████████████████████████████████ 100.00 B (100) 0 B file 0 B net 100.00 B unknown -█████████████████████ 42.00 B app3 (unknown (tid=101)) 0 B file 0 B net 42.00 B unknown - 0 B app (99) 0 B file 0 B net 0 B unknown -Per-process I/O Write -############################################################################### -██████████████████████████████████████████████████ 10.00 B app (99) 0 B file 0 B net 10.00 B unknown - 0 B (100) 0 B file 0 B net 0 B unknown - 0 B app3 (unknown (tid=101)) 0 B file 0 B net 0 B unknown -Files read -############################################################################### -██████████████████████████████████████████████████ 100.00 B testfile fd 3 in (100) -█████████████████████ 42.00 B unknown(app3) fd 3 in app3 (101) -Files write -############################################################################### -██████████████████████████████████████████████████ 10.00 B unknown(app) fd 4 in app (99) -Block I/O Read -############################################################################### -██████████████████████████████████████████████████ 5.00 KB app (pid=99) -Block I/O Write -############################################################################### -██████████████████████████████████████████████████ 5.00 KB app (pid=99) -Disk requests sector count -############################################################################### -██████████████████████████████████████████████████████████████████ 11.00 sectors (8,0) -████████████████████████████████████████████████████████████ 10.00 sectors (252,0) -Disk request count -############################################################################### -███████████████████████████████████████████████████████████████████ 1.00 requests (252,0) -███████████████████████████████████████████████████████████████████ 1.00 requests (8,0) -Disk request average latency -############################################################################### -█████████████████████████████████████████████████████████████████ 1.00 ms (252,0) -█████████████████████████████████████████████████████████████████ 1.00 ms (8,0) -Network received bytes -############################################################################### -██████████████████████████████████████████████████████████ 200.00 B wlan0 -█████████████████████████████ 100.00 B wlan1 -Network sent bytes -############################################################################### - 0 B wlan0 - 0 B wlan1""" + def test_iousagetop(self): + expected = self.get_expected_output('iousagetop.txt') + result = self.get_cmd_output('lttng-iousagetop') - return self.compare_output('%slttng-iousagetop %s "%s"' % ( - self.cmd_root, self.common_options, self.t.trace_root), - expected) + self.assertMultiLineEqual(result, expected) - def run_iolatencytop(self): - expected = """Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.022000000] + def test_iolatencytop(self): + expected = self.get_expected_output('iolatencytop.txt') + result = self.get_cmd_output('lttng-iolatencytop') -Top system call latencies read (usec) -Begin End Name Duration (usec) Size Proc PID Filename -[19:00:01.008000000,19:00:01.009000000] read 1000.000 100.00 B 100 testfile (fd=3) -[19:00:01.008000000,19:00:01.009000000] read 1000.000 100.00 B 100 testfile (fd=3) -[19:00:01.012000000,19:00:01.013000000] read 1000.000 42.00 B app3 101 unknown (fd=3) -[19:00:01.012000000,19:00:01.013000000] read 1000.000 42.00 B app3 101 unknown (fd=3) - -Top system call latencies write (usec) -Begin End Name Duration (usec) Size Proc PID Filename -[19:00:01.004000000,19:00:01.005000000] write 1000.000 10.00 B app 99 unknown (fd=4) -[19:00:01.004000000,19:00:01.005000000] write 1000.000 10.00 B app 99 unknown (fd=4)""" - - return self.compare_output('%slttng-iolatencytop %s "%s"' % ( - self.cmd_root, self.common_options, - self.t.get_trace_root()), expected) - - -def test_answer(): - t = IoTest(verbose=True) - ok = t.run() - assert(ok) - -test_answer() + self.assertMultiLineEqual(result, expected) diff --git a/tests/test_irq.py b/tests/test_irq.py index ce03bd2..d792e68 100644 --- a/tests/test_irq.py +++ b/tests/test_irq.py @@ -1,109 +1,87 @@ -from TraceTest import AnalysesTest -import sys +# The MIT License (MIT) +# +# Copyright (C) 2016 - Julien Desfossez +# Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +from .analysis_test import AnalysisTest -class IrqTest(AnalysesTest): - def __init__(self, delete_trace=True, verbose=False): - super().__init__(delete_trace=delete_trace, - verbose=verbose) - self.test_list = [('irqstats', self.run_irqstats), - ('irqlog', self.run_irqlog)] +class IrqTest(AnalysisTest): def write_trace(self): - self.t.write_softirq_raise(1000 , 1, 1) - self.t.write_softirq_raise(1001 , 3, 1) - self.t.write_softirq_raise(1002 , 1, 9) - self.t.write_softirq_exit(1003 , 0, 4) - self.t.write_softirq_raise(1004 , 3, 9) - self.t.write_softirq_raise(1005 , 3, 7) - self.t.write_softirq_entry(1006 , 3, 1) - self.t.write_softirq_entry(1007 , 1, 1) - self.t.write_softirq_exit(1008 , 1, 1) - self.t.write_softirq_exit(1009 , 3, 1) - self.t.write_softirq_entry(1010 , 1, 9) - self.t.write_softirq_entry(1011 , 3, 7) - self.t.write_softirq_exit(1012 , 1, 9) - self.t.write_softirq_exit(1013 , 3, 7) - self.t.write_softirq_entry(1014 , 3, 9) - self.t.write_softirq_exit(1015 , 3, 9) - self.t.write_irq_handler_entry(1016 , 0, 41, "ahci") - self.t.write_softirq_raise(1017 , 0, 4) - self.t.write_irq_handler_exit(1018 , 0, 41, 1) - self.t.write_softirq_entry(1019 , 0, 4) - self.t.write_softirq_exit(1020 , 0, 4) - self.t.write_irq_handler_entry(1021 , 0, 41, "ahci") - self.t.write_softirq_raise(1022 , 0, 4) - self.t.write_irq_handler_exit(1023 , 0, 41, 1) - self.t.write_softirq_entry(1024 , 0, 4) - self.t.write_softirq_exit(1025 , 0, 4) - self.t.write_irq_handler_entry(1026 , 0, 41, "ahci") - self.t.write_softirq_raise(1027 , 0, 4) - self.t.write_irq_handler_exit(1028 , 0, 41, 1) - self.t.write_softirq_entry(1029 , 0, 4) - self.t.write_softirq_exit(1030 , 0, 4) - self.t.write_irq_handler_entry(1031 , 0, 41, "ahci") - self.t.write_softirq_raise(1032 , 0, 4) - self.t.write_irq_handler_exit(1033 , 0, 41, 1) - self.t.write_softirq_entry(1034 , 0, 4) - self.t.write_softirq_exit(1035 , 0, 4) - self.t.write_irq_handler_entry(1036 , 0, 41, "ahci") - self.t.write_softirq_raise(1037 , 0, 4) - self.t.write_irq_handler_exit(1038 , 0, 41, 1) - self.t.write_softirq_entry(1039 , 0, 4) - self.t.write_softirq_exit(1040 , 0, 4) - self.t.write_irq_handler_entry(1041 , 0, 41, "ahci") - self.t.write_softirq_raise(1042 , 0, 4) - self.t.write_irq_handler_exit(1043 , 0, 41, 1) - self.t.write_softirq_entry(1044 , 0, 4) - self.t.write_softirq_exit(1045 , 0, 4) - self.t.flush() + self.trace_writer.write_softirq_raise(1000, 1, 1) + self.trace_writer.write_softirq_raise(1001, 3, 1) + self.trace_writer.write_softirq_raise(1002, 1, 9) + self.trace_writer.write_softirq_exit(1003, 0, 4) + self.trace_writer.write_softirq_raise(1004, 3, 9) + self.trace_writer.write_softirq_raise(1005, 3, 7) + self.trace_writer.write_softirq_entry(1006, 3, 1) + self.trace_writer.write_softirq_entry(1007, 1, 1) + self.trace_writer.write_softirq_exit(1008, 1, 1) + self.trace_writer.write_softirq_exit(1009, 3, 1) + self.trace_writer.write_softirq_entry(1010, 1, 9) + self.trace_writer.write_softirq_entry(1011, 3, 7) + self.trace_writer.write_softirq_exit(1012, 1, 9) + self.trace_writer.write_softirq_exit(1013, 3, 7) + self.trace_writer.write_softirq_entry(1014, 3, 9) + self.trace_writer.write_softirq_exit(1015, 3, 9) + self.trace_writer.write_irq_handler_entry(1016, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1017, 0, 4) + self.trace_writer.write_irq_handler_exit(1018, 0, 41, 1) + self.trace_writer.write_softirq_entry(1019, 0, 4) + self.trace_writer.write_softirq_exit(1020, 0, 4) + self.trace_writer.write_irq_handler_entry(1021, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1022, 0, 4) + self.trace_writer.write_irq_handler_exit(1023, 0, 41, 1) + self.trace_writer.write_softirq_entry(1024, 0, 4) + self.trace_writer.write_softirq_exit(1025, 0, 4) + self.trace_writer.write_irq_handler_entry(1026, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1027, 0, 4) + self.trace_writer.write_irq_handler_exit(1028, 0, 41, 1) + self.trace_writer.write_softirq_entry(1029, 0, 4) + self.trace_writer.write_softirq_exit(1030, 0, 4) + self.trace_writer.write_irq_handler_entry(1031, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1032, 0, 4) + self.trace_writer.write_irq_handler_exit(1033, 0, 41, 1) + self.trace_writer.write_softirq_entry(1034, 0, 4) + self.trace_writer.write_softirq_exit(1035, 0, 4) + self.trace_writer.write_irq_handler_entry(1036, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1037, 0, 4) + self.trace_writer.write_irq_handler_exit(1038, 0, 41, 1) + self.trace_writer.write_softirq_entry(1039, 0, 4) + self.trace_writer.write_softirq_exit(1040, 0, 4) + self.trace_writer.write_irq_handler_entry(1041, 0, 41, 'ahci') + self.trace_writer.write_softirq_raise(1042, 0, 4) + self.trace_writer.write_irq_handler_exit(1043, 0, 41, 1) + self.trace_writer.write_softirq_entry(1044, 0, 4) + self.trace_writer.write_softirq_exit(1045, 0, 4) + self.trace_writer.flush() - def run_irqstats(self): - expected = """Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.045000000] -Hard IRQ Duration (us) - count min avg max stdev -----------------------------------------------------------------------------------| -41: 6 2000.000 2000.000 2000.000 0.000 | + def test_irqstats(self): + expected = self.get_expected_output('irqstats.txt') + result = self.get_cmd_output('lttng-irqstats') -Soft IRQ Duration (us) Raise latency (us) - count min avg max stdev | count min avg max stdev -----------------------------------------------------------------------------------|------------------------------------------------------------ -1: 2 1000.000 2000.000 3000.000 1414.214 | 2 5000.000 6000.000 7000.000 1414.214 -4: 6 1000.000 1000.000 1000.000 0.000 | 6 2000.000 2000.000 2000.000 0.000 -7: 1 2000.000 2000.000 2000.000 ? | 1 6000.000 6000.000 6000.000 ? -9: 2 1000.000 1500.000 2000.000 707.107 | 2 8000.000 9000.000 10000.000 1414.214""" + self.assertMultiLineEqual(result, expected) - return self.compare_output('%slttng-irqstats %s "%s"' % ( - self.cmd_root, self.common_options, self.t.trace_root), - expected) + def test_irqlog(self): + expected = self.get_expected_output('irqlog.txt') + result = self.get_cmd_output('lttng-irqlog') - def run_irqlog(self): - expected = """Timerange: [1969-12-31 19:00:01.000000000, 1969-12-31 19:00:01.045000000] -Begin End Duration (us) CPU Type # Name -[19:00:01.007000000, 19:00:01.008000000] 1000.000 1 SoftIRQ 1 TIMER_SOFTIRQ (raised at 19:00:01.000000000) -[19:00:01.006000000, 19:00:01.009000000] 3000.000 3 SoftIRQ 1 TIMER_SOFTIRQ (raised at 19:00:01.001000000) -[19:00:01.010000000, 19:00:01.012000000] 2000.000 1 SoftIRQ 9 RCU_SOFTIRQ (raised at 19:00:01.002000000) -[19:00:01.011000000, 19:00:01.013000000] 2000.000 3 SoftIRQ 7 SCHED_SOFTIRQ (raised at 19:00:01.005000000) -[19:00:01.014000000, 19:00:01.015000000] 1000.000 3 SoftIRQ 9 RCU_SOFTIRQ (raised at 19:00:01.004000000) -[19:00:01.016000000, 19:00:01.018000000] 2000.000 0 IRQ 41 ahci -[19:00:01.019000000, 19:00:01.020000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.017000000) -[19:00:01.021000000, 19:00:01.023000000] 2000.000 0 IRQ 41 ahci -[19:00:01.024000000, 19:00:01.025000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.022000000) -[19:00:01.026000000, 19:00:01.028000000] 2000.000 0 IRQ 41 ahci -[19:00:01.029000000, 19:00:01.030000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.027000000) -[19:00:01.031000000, 19:00:01.033000000] 2000.000 0 IRQ 41 ahci -[19:00:01.034000000, 19:00:01.035000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.032000000) -[19:00:01.036000000, 19:00:01.038000000] 2000.000 0 IRQ 41 ahci -[19:00:01.039000000, 19:00:01.040000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.037000000) -[19:00:01.041000000, 19:00:01.043000000] 2000.000 0 IRQ 41 ahci -[19:00:01.044000000, 19:00:01.045000000] 1000.000 0 SoftIRQ 4 BLOCK_SOFTIRQ (raised at 19:00:01.042000000)""" - - return self.compare_output('%slttng-irqlog %s "%s"' % ( - self.cmd_root, self.common_options, self.t.trace_root), - expected) - - -def test_answer(): - t = IrqTest(verbose=True) - ok = t.run() - assert(ok) + self.assertMultiLineEqual(result, expected) diff --git a/tests/TraceTest.py b/tests/trace_writer.py similarity index 94% rename from tests/TraceTest.py rename to tests/trace_writer.py index 8cbf043..dc69051 100644 --- a/tests/TraceTest.py +++ b/tests/trace_writer.py @@ -1,15 +1,35 @@ +# The MIT License (MIT) +# +# Copyright (C) 2016 - Julien Desfossez +# Antoine Busque +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import sys import os import shutil import tempfile -import difflib -import subprocess from babeltrace import CTFWriter, CTFStringEncoding -class TraceTest(): - def __init__(self, delete_trace=True): - self.delete_trace = delete_trace +class TraceWriter(): + def __init__(self): self._trace_root = tempfile.mkdtemp() self.trace_path = os.path.join(self.trace_root, "kernel") self.create_writer() @@ -18,10 +38,6 @@ class TraceTest(): self.define_events() self.create_stream() - def __del__(self): - if self.delete_trace: - self.rm_trace() - @property def trace_root(self): return self._trace_root @@ -516,43 +532,3 @@ class TraceTest(): current += period self.write_sched_switch(current, cpu_id, comm2, tid2, comm1, tid1) current += period - - def compare_output(self, cmd, expected): - line_sep = '\n' - result = subprocess.getoutput(cmd) - diff = difflib.ndiff(expected.split(line_sep), result.split(line_sep)) - - for line in diff: - if line[0] != ' ': - # result doesn't match expected. Print the diff and - # return False - print(line_sep.join(diff)) - return False - - return True - - -class AnalysesTest(): - def __init__(self, delete_trace=True, verbose=False): - self.verbose = verbose - self.t = TraceTest(delete_trace=delete_trace) - self.common_options = '--no-progress --skip-validation' - self.cmd_root = './' - self.log('Trace in %s' % (self.t.trace_root)) - - def log(self, msg): - if self.verbose: - print(msg) - - def compare_output(self, cmd, expected): - return self.t.compare_output(cmd, expected) - - def run(self): - ok = True - self.write_trace() - for t in self.test_list: - ret = t[1]() - self.log('%s: %s' % (t[0], ret)) - if not ret: - ok = False - return ok -- 2.34.1