Re: [Lldb-commits] [PATCH] D24890: implement timeout sample support for Linux

2016-09-26 Thread Todd Fiala via lldb-commits
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

2016-09-26 Thread Todd Fiala via lldb-commits
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

2016-09-26 Thread Pavel Labath via lldb-commits
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

2016-09-23 Thread Todd Fiala via lldb-commits
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

2016-09-23 Thread Todd Fiala via lldb-commits
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