Skip to content

Commit 75fd345

Browse files
YvesDuppablogsal
authored andcommitted
[3.14] gh-140729: Fix the cProfile module when the executed script contains calls to multiprocessing.Process (GH-144715)
(cherry picked from commit d7275d3) Co-authored-by: Duprat <yduprat@gmail.com> Co-authored-by: Pablo Galindo Salgado <pablogsal@gmail.com>
1 parent 25a53d9 commit 75fd345

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

Lib/cProfile.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ def main():
183183
# in the module's namespace.
184184
globs = module.__dict__
185185
globs.update({
186-
'__spec__': spec,
186+
# Set __spec__ to None so the profiled program behaves like a
187+
# script run directly (gh-140729).
188+
'__spec__': None,
187189
'__file__': spec.origin,
188190
'__name__': spec.name,
189191
'__package__': None,

Lib/test/test_cprofile.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

@@ -171,6 +170,40 @@ class Foo:
171170
f.close()
172171
assert_python_ok('-m', "cProfile", f.name)
173172

173+
def _test_process_run_pickle(self, start_method):
174+
val = 10
175+
with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f:
176+
f.write(textwrap.dedent(
177+
f'''\
178+
import multiprocessing
179+
180+
def worker(x):
181+
print(__name__)
182+
exit(x ** 2)
183+
184+
if __name__ == "__main__":
185+
multiprocessing.set_start_method('{start_method}')
186+
p = multiprocessing.Process(target=worker, args=({val},))
187+
p.start()
188+
p.join()
189+
print("p.exitcode =", p.exitcode)
190+
'''))
191+
f.close()
192+
_, out, err = assert_python_ok('-m', "cProfile", f.name)
193+
self.assertIn(b"__mp_main__", out)
194+
self.assertIn(bytes(f"exitcode = {val**2}", encoding='utf8'), out)
195+
self.assertNotIn(b"Can't pickle", err)
196+
197+
def test_process_spawn_pickle(self):
198+
# gh-140729: test use Process in cProfile.
199+
self._test_process_run_pickle('spawn')
200+
201+
@unittest.skipIf(sys.platform == 'win32',
202+
"No 'forkserver' start method on Windows")
203+
def test_process_forkserver_pickle(self):
204+
# gh-140729: test use Process in cProfile.
205+
self._test_process_run_pickle('forkserver')
206+
174207

175208
def main():
176209
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)