Re: [Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux
tfiala added a comment. BTW, regarding this part: > On Ubuntu 16.04, the requisite support can be retrieved with: > > sudo apt-get install perf-tools-unstable This was incorrect. The perf tool was actually present even without the perf-tools-unstable on Ubuntu 16.04 x86_64. It is just that there are more tools for processing perf output available with that package, but this change doesn't require any of them. /usr/bin/perf comes from the linux-tools-common package on Ubuntu. I tried testing with and without that package installed. Repository: rL LLVM https://reviews.llvm.org/D24890 ___ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
Re: [Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux
This revision was automatically updated to reflect the committed changes. Closed by commit rL282436: added Linux support for test timeout sampling (authored by tfiala). Changed prior to commit: https://reviews.llvm.org/D24890?vs=72382&id=72553#toc Repository: rL LLVM https://reviews.llvm.org/D24890 Files: lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/linux.py lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py lldb/trunk/packages/Python/lldbsuite/test/dosep.py lldb/trunk/packages/Python/lldbsuite/test/test_runner/process_control.py Index: lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/linux.py === --- lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/linux.py +++ lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/linux.py @@ -0,0 +1,76 @@ +"""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) Index: lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py === --- lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py +++ lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py @@ -38,7 +38,7 @@ 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") Index: lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py === --- lldb/trunk/packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py +++ lldb/trunk/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, Que
Re: [Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux
labath accepted this revision. labath added a comment. This revision is now accepted and ready to land. lgtm https://reviews.llvm.org/D24890 ___ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
Re: [Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux
tfiala added inline comments. Comment at: packages/Python/lldbsuite/pre_kill_hook/linux.py:68 @@ +67,3 @@ +else: +raise Exception("failed to call 'perf record .., error: ") + Haha woops - that should be: ``` raise Exception("failed to call 'perf record ..., error code: {}".format(returncode)) ``` I'll fix that in the final. https://reviews.llvm.org/D24890 ___ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux
tfiala created this revision. tfiala added reviewers: labath, tberghammer. tfiala added a subscriber: lldb-commits. This is the Linux counterpart to the recently-added macOS-side support for sampling a test process that times out, prior to killing it. This implementation is based on the Linux perf tools. Each distribution will have a different way to install it. The hook is skipped if Linux perf is not available. On Ubuntu 16.04, the requisite support can be retrieved with: ``` sudo apt-get install perf-tools-unstable ``` Like the macOS side, the content out the time spent at each call point per backtrace is specified in a file in the session directory of the format: {TestName.py}-{pid}.sample https://reviews.llvm.org/D24890 Files: packages/Python/lldbsuite/pre_kill_hook/linux.py packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py Index: packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py === --- /dev/null +++ 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_c