1 """Test the pre-kill hook on Linux."""
2 from __future__ import print_function
5 from multiprocessing import Process, Queue
9 from unittest import main, TestCase
12 from six import StringIO
15 def do_child_thread():
19 x = x + 42 * os.getpid()
23 def do_child_process(child_work_queue, parent_work_queue, verbose):
28 print("child: pid {} started, sending to parent".format(pid))
29 parent_work_queue.put(pid)
31 # Spin up a daemon thread to do some "work", which will show
32 # up in a sample of this process.
34 worker = threading.Thread(target=do_child_thread)
39 print("child: waiting for shut-down request from parent")
40 child_work_queue.get()
42 print("child: received shut-down request. Child exiting.")
45 class LinuxPreKillTestCase(TestCase):
47 def __init__(self, methodName):
48 super(LinuxPreKillTestCase, self).__init__(methodName)
50 self.child_work_queue = None
56 print("parent: sending shut-down request to child")
58 self.child_work_queue.put("hello, child")
61 print("parent: child is fully shut down")
63 def test_sample(self):
64 # Ensure we're Darwin.
65 if platform.system() != 'Linux':
66 self.skipTest("requires a Linux-based OS")
68 # Ensure we have the 'perf' tool. If not, skip the test.
70 perf_version = subprocess.check_output(["perf", "version"])
71 if perf_version is None or not (
72 perf_version.startswith("perf version")):
73 raise Exception("The perf executable doesn't appear"
74 " to be the Linux perf tools perf")
76 self.skipTest("requires the Linux perf tools 'perf' command")
78 # Start the child process.
79 self.child_work_queue = Queue()
80 parent_work_queue = Queue()
81 self.process = Process(target=do_child_process,
82 args=(self.child_work_queue, parent_work_queue,
85 print("parent: starting child")
88 # Wait for the child to report its pid. Then we know we're running.
90 print("parent: waiting for child to start")
91 child_pid = parent_work_queue.get()
93 # Sample the child process.
94 from linux import do_pre_kill
96 "archs": [platform.machine()],
97 "platform_name": None,
99 "platform_working_dir": None
103 print("parent: running pre-kill action on child")
104 output_io = StringIO()
105 do_pre_kill(child_pid, context_dict, output_io)
106 output = output_io.getvalue()
109 print("parent: do_pre_kill() wrote the following output:", output)
110 self.assertIsNotNone(output)
112 # We should have a samples count entry.
114 self.assertTrue("Samples:" in output, "should have found a 'Samples:' "
115 "field in the sampled process output")
117 # We should see an event count entry
118 event_count_re = re.compile(r"Event count[^:]+:\s+(\d+)")
119 match = event_count_re.search(output)
120 self.assertIsNotNone(match, "should have found the event count entry "
123 print("cpu-clock events:", match.group(1))
125 # We should see some percentages in the file.
126 percentage_re = re.compile(r"\d+\.\d+%")
127 match = percentage_re.search(output)
128 self.assertIsNotNone(match, "should have found at least one percentage "
129 "in the sample output")
132 if __name__ == "__main__":