Skip to content

Commit 81986cb

Browse files
[3.15] gh-140729: Fix the cProfile module when the executed script contains calls to multiprocessing.Process (GH-144715) (#153243)
1 parent cca9d1c commit 81986cb

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

Lib/profiling/tracing/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,9 @@ def main():
197197
# in the module's namespace.
198198
globs = module.__dict__
199199
globs.update({
200-
'__spec__': spec,
200+
# Set __spec__ to None so the profiled program behaves like a
201+
# script run directly (gh-140729).
202+
'__spec__': None,
201203
'__file__': spec.origin,
202204
'__name__': spec.name,
203205
'__package__': None,

Lib/test/test_profiling/test_tracing_profiler.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Test suite for the cProfile module."""
2-
32
import sys
43
import unittest
54

@@ -192,6 +191,40 @@ class Foo:
192191
f.close()
193192
assert_python_ok('-m', "cProfile", f.name)
194193

194+
def _test_process_run_pickle(self, start_method):
195+
val = 10
196+
with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f:
197+
f.write(textwrap.dedent(
198+
f'''\
199+
import multiprocessing
200+
201+
def worker(x):
202+
print(__name__)
203+
exit(x ** 2)
204+
205+
if __name__ == "__main__":
206+
multiprocessing.set_start_method('{start_method}')
207+
p = multiprocessing.Process(target=worker, args=({val},))
208+
p.start()
209+
p.join()
210+
print("p.exitcode =", p.exitcode)
211+
'''))
212+
f.close()
213+
_, out, err = assert_python_ok('-m', "cProfile", f.name)
214+
self.assertIn(b"__mp_main__", out)
215+
self.assertIn(bytes(f"exitcode = {val**2}", encoding='utf8'), out)
216+
self.assertNotIn(b"Can't pickle", err)
217+
218+
def test_process_spawn_pickle(self):
219+
# gh-140729: test use Process in cProfile.
220+
self._test_process_run_pickle('spawn')
221+
222+
@unittest.skipIf(sys.platform == 'win32',
223+
"No 'forkserver' start method on Windows")
224+
def test_process_forkserver_pickle(self):
225+
# gh-140729: test use Process in cProfile.
226+
self._test_process_run_pickle('forkserver')
227+
195228

196229
def main():
197230
if '-r' not in sys.argv:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a pickling error in the ``cProfile`` module when profiling a script that
2+
uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver``
3+
start methods.

0 commit comments

Comments
 (0)