summaryrefslogtreecommitdiffstats
path: root/lldb/packages/Python/lldbsuite/pre_kill_hook/tests
diff options
context:
space:
mode:
authorTodd Fiala <todd.fiala@gmail.com>2016-09-26 20:25:47 +0000
committerTodd Fiala <todd.fiala@gmail.com>2016-09-26 20:25:47 +0000
commit2cd84c905df4fe9a6005320a45e98cd4b8ade045 (patch)
tree4165388cdc668b91a41117d96078e15e6671dce0 /lldb/packages/Python/lldbsuite/pre_kill_hook/tests
parent9eddaeb5340035f1ed36940f7478999616a898f0 (diff)
downloadbcm5719-llvm-2cd84c905df4fe9a6005320a45e98cd4b8ade045.tar.gz
bcm5719-llvm-2cd84c905df4fe9a6005320a45e98cd4b8ade045.zip
added Linux support for test timeout sampling
This is the Linux counterpart to the sampling support I added on the macOS side. This change also introduces zip-file compression if the size of the sample output is greater than 10 KB. The Linux side can be quite large and the textual content is averaging over a 10x compression factor on tests that I force to time out. When compression takes place, the filename becomes: {session_dir}/{TestFilename.py}-{pid}.sample.zip This support relies on the linux 'perf' tool. If it isn't present, the behavior is to ignore pre-kill processing of the timed out test process. Note calling the perf tool under the timeout command appears to nuke the profiled process. This was causing the timeout kill logic to fail due to the process having disappeared. I modified the kill logic to catch the case of the process not existing, and I have it ignore the kill request in that case. Any other exception is still raised. Reviewers: labath Subscribers: lldb-commits Differential Revision: https://reviews.llvm.org/D24890 llvm-svn: 282436
Diffstat (limited to 'lldb/packages/Python/lldbsuite/pre_kill_hook/tests')
-rw-r--r--lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py2
-rw-r--r--lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py133
2 files changed, 134 insertions, 1 deletions
diff --git a/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py b/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py
index 48d286c909e..810b364b07c 100644
--- a/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py
+++ b/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py
@@ -38,7 +38,7 @@ class DarwinPreKillTestCase(TestCase):
print("parent: sending shut-down request to child")
if self.process:
self.child_work_queue.put("hello, child")
- self.process.join()
+ self.process.join()
if self.verbose:
print("parent: child is fully shut down")
diff --git a/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py b/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py
new file mode 100644
index 00000000000..ab989df0d20
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py
@@ -0,0 +1,133 @@
+"""Test the pre-kill hook on Linux."""
+from __future__ import print_function
+
+# system imports
+from multiprocessing import Process, Queue
+import platform
+import re
+import subprocess
+from unittest import main, TestCase
+
+# third party
+from six import StringIO
+
+
+def do_child_thread():
+ import os
+ x = 0
+ while True:
+ x = x + 42 * os.getpid()
+ return x
+
+
+def do_child_process(child_work_queue, parent_work_queue, verbose):
+ import os
+
+ pid = os.getpid()
+ if verbose:
+ print("child: pid {} started, sending to parent".format(pid))
+ parent_work_queue.put(pid)
+
+ # Spin up a daemon thread to do some "work", which will show
+ # up in a sample of this process.
+ import threading
+ worker = threading.Thread(target=do_child_thread)
+ worker.daemon = True
+ worker.start()
+
+ if verbose:
+ print("child: waiting for shut-down request from parent")
+ child_work_queue.get()
+ if verbose:
+ print("child: received shut-down request. Child exiting.")
+
+
+class LinuxPreKillTestCase(TestCase):
+
+ def __init__(self, methodName):
+ super(LinuxPreKillTestCase, self).__init__(methodName)
+ self.process = None
+ self.child_work_queue = None
+ self.verbose = False
+ # self.verbose = True
+
+ def tearDown(self):
+ if self.verbose:
+ print("parent: sending shut-down request to child")
+ if self.process:
+ self.child_work_queue.put("hello, child")
+ self.process.join()
+ if self.verbose:
+ print("parent: child is fully shut down")
+
+ def test_sample(self):
+ # Ensure we're Darwin.
+ if platform.system() != 'Linux':
+ self.skipTest("requires a Linux-based OS")
+
+ # Ensure we have the 'perf' tool. If not, skip the test.
+ try:
+ perf_version = subprocess.check_output(["perf", "version"])
+ if perf_version is None or not (
+ perf_version.startswith("perf version")):
+ raise Exception("The perf executable doesn't appear"
+ " to be the Linux perf tools perf")
+ except Exception:
+ self.skipTest("requires the Linux perf tools 'perf' command")
+
+ # Start the child process.
+ self.child_work_queue = Queue()
+ parent_work_queue = Queue()
+ self.process = Process(target=do_child_process,
+ args=(self.child_work_queue, parent_work_queue,
+ self.verbose))
+ if self.verbose:
+ print("parent: starting child")
+ self.process.start()
+
+ # Wait for the child to report its pid. Then we know we're running.
+ if self.verbose:
+ print("parent: waiting for child to start")
+ child_pid = parent_work_queue.get()
+
+ # Sample the child process.
+ from linux import do_pre_kill
+ context_dict = {
+ "archs": [platform.machine()],
+ "platform_name": None,
+ "platform_url": None,
+ "platform_working_dir": None
+ }
+
+ if self.verbose:
+ print("parent: running pre-kill action on child")
+ output_io = StringIO()
+ do_pre_kill(child_pid, context_dict, output_io)
+ output = output_io.getvalue()
+
+ if self.verbose:
+ print("parent: do_pre_kill() wrote the following output:", output)
+ self.assertIsNotNone(output)
+
+ # We should have a samples count entry.
+ # Samples:
+ self.assertTrue("Samples:" in output, "should have found a 'Samples:' "
+ "field in the sampled process output")
+
+ # We should see an event count entry
+ event_count_re = re.compile(r"Event count[^:]+:\s+(\d+)")
+ match = event_count_re.search(output)
+ self.assertIsNotNone(match, "should have found the event count entry "
+ "in sample output")
+ if self.verbose:
+ print("cpu-clock events:", match.group(1))
+
+ # We should see some percentages in the file.
+ percentage_re = re.compile(r"\d+\.\d+%")
+ match = percentage_re.search(output)
+ self.assertIsNotNone(match, "should have found at least one percentage "
+ "in the sample output")
+
+
+if __name__ == "__main__":
+ main()
OpenPOWER on IntegriCloud