diff options
Diffstat (limited to 'packages/Python/lldbsuite/pre_kill_hook')
7 files changed, 0 insertions, 418 deletions
| diff --git a/packages/Python/lldbsuite/pre_kill_hook/README.md b/packages/Python/lldbsuite/pre_kill_hook/README.md deleted file mode 100644 index 921eedb4a869..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# pre\_kill\_hook package - -## Overview - -The pre\_kill\_hook package provides a per-platform method for running code -after a test process times out but before the concurrent test runner kills the -timed-out process. - -## Detailed Description of Usage - -If a platform defines the hook, then the hook gets called right after a timeout -is detected in a test run, but before the process is killed. - -The pre-kill-hook mechanism works as follows: - -* When a timeout is detected in the process_control.ProcessDriver class that -  runs the per-test lldb process, a new overridable on\_timeout\_pre\_kill() method -  is called on the ProcessDriver instance. - -* The concurrent test driver's derived ProcessDriver overrides this method. It -  looks to see if a module called -  "lldbsuite.pre\_kill\_hook.{platform-system-name}" module exists, where -  platform-system-name is replaced with platform.system().lower().  (e.g. -  "Darwin" becomes the darwin.py module). -   -  * If that module doesn't exist, the rest of the new behavior is skipped. - -  * If that module does exist, it is loaded, and the method -    "do\_pre\_kill(process\_id, context\_dict, output\_stream)" is called. If -    that method throws an exception, we log it and we ignore further processing -    of the pre-killed process. - -  * The process\_id argument of the do\_pre\_kill function is the process id as -    returned by the ProcessDriver.pid property. -   -  * The output\_stream argument of the do\_pre\_kill function takes a file-like -    object. Output to be collected from doing any processing on the -    process-to-be-killed should be written into the file-like object. The -    current impl uses a six.StringIO and then writes this output to -    {TestFilename}-{pid}.sample in the session directory. -     -* Platforms where platform.system() is "Darwin" will get a pre-kill action that -  runs the 'sample' program on the lldb that has timed out. That data will be -  collected on CI and analyzed to determine what is happening during timeouts. -  (This has an advantage over a core in that it is much smaller and that it -  clearly demonstrates any liveness of the process, if there is any). - -## Running the tests - -To run the tests in the pre\_kill\_hook package, open a console, change into -this directory and run the following: - -``` -python -m unittest discover -``` diff --git a/packages/Python/lldbsuite/pre_kill_hook/__init__.py b/packages/Python/lldbsuite/pre_kill_hook/__init__.py deleted file mode 100644 index c3a852ea1bfe..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Initialize the package.""" diff --git a/packages/Python/lldbsuite/pre_kill_hook/darwin.py b/packages/Python/lldbsuite/pre_kill_hook/darwin.py deleted file mode 100644 index 2bee65a01e3f..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/darwin.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Provides a pre-kill method to run on macOS.""" -from __future__ import print_function - -# system imports -import subprocess -import sys - -# third-party module imports -import six - - -def do_pre_kill(process_id, runner_context, output_stream, sample_time=3): -    """Samples the given process id, and puts the output to output_stream. - -    @param process_id the local process to sample. - -    @param runner_context a dictionary of details about the architectures -    and platform on which the given process is running.  Expected keys are -    archs (array of architectures), platform_name, platform_url, and -    platform_working_dir. - -    @param output_stream file-like object that should be used to write the -    results of sampling. - -    @param sample_time specifies the time in seconds that should be captured. -    """ - -    # Validate args. -    if runner_context is None: -        raise Exception("runner_context argument is required") -    if not isinstance(runner_context, dict): -        raise Exception("runner_context argument must be a dictionary") - -    # We will try to run sample on the local host only if there is no URL -    # to a remote. -    if "platform_url" in runner_context and ( -            runner_context["platform_url"] is not None): -        import pprint -        sys.stderr.write( -            "warning: skipping timeout pre-kill sample invocation because we " -            "don't know how to run on a remote yet. runner_context={}\n" -            .format(pprint.pformat(runner_context))) - -    output = subprocess.check_output(['sample', six.text_type(process_id), -                                      str(sample_time)]) -    output_stream.write(output) diff --git a/packages/Python/lldbsuite/pre_kill_hook/linux.py b/packages/Python/lldbsuite/pre_kill_hook/linux.py deleted file mode 100644 index d4cd9be27c82..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/linux.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Provides a pre-kill method to run on Linux. - -This timeout pre-kill method relies on the Linux perf-tools -distribution.  The appropriate way to obtain this set of tools -will depend on the Linux distribution. - -For Ubuntu 16.04, the invoke the following command: -sudo apt-get install perf-tools-unstable -""" -from __future__ import print_function - -# system imports -import os -import subprocess -import sys -import tempfile - - -def do_pre_kill(process_id, runner_context, output_stream, sample_time=3): -    """Samples the given process id, and puts the output to output_stream. - -    @param process_id the local process to sample. - -    @param runner_context a dictionary of details about the architectures -    and platform on which the given process is running.  Expected keys are -    archs (array of architectures), platform_name, platform_url, and -    platform_working_dir. - -    @param output_stream file-like object that should be used to write the -    results of sampling. - -    @param sample_time specifies the time in seconds that should be captured. -    """ - -    # Validate args. -    if runner_context is None: -        raise Exception("runner_context argument is required") -    if not isinstance(runner_context, dict): -        raise Exception("runner_context argument must be a dictionary") - -    # We will try to run sample on the local host only if there is no URL -    # to a remote. -    if "platform_url" in runner_context and ( -            runner_context["platform_url"] is not None): -        import pprint -        sys.stderr.write( -            "warning: skipping timeout pre-kill sample invocation because we " -            "don't know how to run on a remote yet. runner_context={}\n" -            .format(pprint.pformat(runner_context))) - -    # We're going to create a temp file, and immediately overwrite it with the -    # following command.  This just ensures we don't have any races in -    # creation of the temporary sample file. -    fileno, filename = tempfile.mkstemp(suffix='perfdata') -    os.close(fileno) -    fileno = None - -    try: -        with open(os.devnull, 'w') as devnull: -            returncode = subprocess.call(['timeout', str(sample_time), 'perf', -                                          'record', '-g', '-o', filename, '-p', str(process_id)], -                                         stdout=devnull, stderr=devnull) -        if returncode == 0 or returncode == 124: -            # This is okay - this is the timeout return code, which is totally -            # expected. -            pass -        else: -            raise Exception("failed to call 'perf record .., error: {}".format( -                returncode)) - -        with open(os.devnull, 'w') as devnull: -            output = subprocess.check_output(['perf', 'report', '--call-graph', -                                              '--stdio', '-i', filename], stderr=devnull) -        output_stream.write(output) -    finally: -        os.remove(filename) diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py b/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py +++ /dev/null diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py b/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py deleted file mode 100644 index 810b364b07c3..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Test the pre-kill hook on Darwin.""" -from __future__ import print_function - -# system imports -from multiprocessing import Process, Queue -import platform -import re -from unittest import main, TestCase - -# third party -from six import StringIO - - -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) -    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 DarwinPreKillTestCase(TestCase): - -    def __init__(self, methodName): -        super(DarwinPreKillTestCase, self).__init__(methodName) -        self.process = None -        self.child_work_queue = None -        self.verbose = False - -    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() != 'Darwin': -            self.skipTest("requires a Darwin-based OS") - -        # 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 darwin 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 line with: -        # Process:  .* [{pid}] -        process_re = re.compile(r"Process:[^[]+\[([^]]+)\]") -        match = process_re.search(output) -        self.assertIsNotNone(match, "should have found process id for " -                             "sampled process") -        self.assertEqual(1, len(match.groups())) -        self.assertEqual(child_pid, int(match.group(1))) - -        # We should see a Call graph: section. -        callgraph_re = re.compile(r"Call graph:") -        match = callgraph_re.search(output) -        self.assertIsNotNone(match, "should have found the Call graph section" -                             "in sample output") - -        # We should see a Binary Images: section. -        binary_images_re = re.compile(r"Binary Images:") -        match = binary_images_re.search(output) -        self.assertIsNotNone(match, "should have found the Binary Images " -                             "section in sample output") - - -if __name__ == "__main__": -    main() diff --git a/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py b/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py deleted file mode 100644 index ab989df0d203..000000000000 --- a/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py +++ /dev/null @@ -1,133 +0,0 @@ -"""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() | 
