Skip to content

Commit d7275d3

Browse files
YvesDuppablogsal
andauthored
gh-140729: Fix the cProfile module when the executed script contains calls to multiprocessing.Process (#144715)
Co-authored-by: Pablo Galindo Salgado <pablogsal@gmail.com>
1 parent dea93ce commit d7275d3

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

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

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

197230
def main():
198231
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)