Skip to content

cProfile does not work in pdb #102249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
impact27 opened this issue Feb 25, 2023 · 13 comments
Closed

cProfile does not work in pdb #102249

impact27 opened this issue Feb 25, 2023 · 13 comments
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error

Comments

@impact27
Copy link
Contributor

impact27 commented Feb 25, 2023

Bug report

While debugging, cProfile fails to work, while profile does work, see session below:

Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb
>>> db = pdb.Pdb()
>>> db.run("aaa")
> <string>(1)<module>()
(Pdb) import profile, cProfile
(Pdb) cProfile.run("print(0)")
0
*** TypeError: Cannot create or construct a <class 'pstats.Stats'> object from <cProfile.Profile object at 0x1028d5660>
(Pdb) profile.run("print(0)")
0
         1 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 profile:0(print(0))
        0    0.000             0.000          profile:0(profiler)


(Pdb) q
>>> cProfile.run("print(0)")
0
         4 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


>>> profile.run("print(0)")
0
         5 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.000    0.000    0.000    0.000 :0(print)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 profile:0(print(0))
        0    0.000             0.000          profile:0(profiler)


>>> 

Your environment

  • CPython versions tested on: Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
  • Operating system and architecture: Apple M1 Max - 13.1 (22C65)

Linked PRs

@impact27 impact27 added the type-bug An unexpected behavior, bug, or error label Feb 25, 2023
@impact27
Copy link
Contributor Author

Apparently the problem is with settrace:

Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def fun(frame, event, arg):
...     import cProfile
...     cProfile.run("print(0)")
...     sys.settrace(None)
... 
>>> import sys
>>> sys.settrace(fun)
>>> print(1)
0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fun
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/cProfile.py", line 16, in run
    return _pyprofile._Utils(Profile).run(statement, filename, sort)
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/profile.py", line 57, in run
    self._show(prof, filename, sort)
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/profile.py", line 72, in _show
    prof.print_stats(sort)
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/cProfile.py", line 42, in print_stats
    pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats()
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/pstats.py", line 114, in __init__
    self.init(arg)
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/pstats.py", line 128, in init
    self.load_stats(arg)
  File "/opt/homebrew/Cellar/[email protected]/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/pstats.py", line 154, in load_stats
    raise TypeError("Cannot create or construct a %r object from %r"
TypeError: Cannot create or construct a <class 'pstats.Stats'> object from <cProfile.Profile object at 0x1029d6980>
>>> 

@impact27
Copy link
Contributor Author

The problem is that the profiling function (set by sys.setprofile) is not called while tracing. I have a minimal example:

Python 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> def fun_prof(frame, event, arg):
...     print("profiling")
... 
>>> def fun_trace(frame, event, arg):
...     print("tracing")
...     sys.setprofile(fun_prof)
...     print("Call func")
...     sys.setprofile(None)
...     sys.settrace(None)
... 
>>> sys.settrace(fun_trace)
>>> print(0)
tracing
Call func
0
>>> 

@impact27
Copy link
Contributor Author

I can use sys.call_tracing as a workaround, but https://docs.python.org/3/library/sys.html#sys.call_tracing doesn't mention anything about profiling, only tracing:

Call func(*args), while tracing is enabled. The tracing state is saved, and restored afterwards. This is intended to be called from a debugger from a checkpoint, to recursively debug some other code.

@arhadthedev arhadthedev added the stdlib Python modules in the Lib dir label Feb 26, 2023
@arhadthedev
Copy link
Member

@iritkatriel @gvanrossum as more-than-once committers into pdb and cProfile correspondingly still active.

@gvanrossum
Copy link
Member

I'm sorry, I no longer have a working knowledge of these APIs. Historically, it never occurred to me that these APIs would be combined.

@CAM-Gerlach CAM-Gerlach added extension-modules C modules in the Modules dir and removed stdlib Python modules in the Lib dir labels Feb 26, 2023
@CAM-Gerlach
Copy link
Member

FWIW, I can repro this on 3.11.0 on Windows:

Python 3.11.0 | packaged by conda-forge | (main, Oct 25 2022, 06:12:32) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb
>>> db = pdb.Pdb()
>>> db.run("aaa")
> <string>(1)<module>()
(Pdb) import profile, cProfile
(Pdb) profile.run("print(0)")
0
         1 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 profile:0(print(0))
        0    0.000             0.000          profile:0(profiler)


(Pdb) cProfile.run("print(0)")
0
*** TypeError: Cannot create or construct a <class 'pstats.Stats'> object from <cProfile.Profile object at 0x0000000003814C20>
(Pdb)

@impact27
Copy link
Contributor Author

I guess the best way to address this would be to update the doc so it is clear that sys.call_tracing works for both sys.settrace and sys.setprofile, at least in https://docs.python.org/3/library/sys.html#sys.call_tracing and maybe a note on https://docs.python.org/3/library/sys.html#sys.setprofile . The name "call_tracing" suggest it would only work for sys.settrace.

If I can add a small feature request: sys.call_tracing(func, args) doesn't take kwargs, which would be great.

@gaogaotiantian
Copy link
Member

I think the rule is - you can't do settrace in profiling function and you can't do setprofile in tracing function. Otherwise it's just too easy to create an infinite recursion - you profiling function will trigger tracing function and the triggered tracing function will trigger profilng function again.

@CAM-Gerlach
Copy link
Member

If I can add a small feature request: sys.call_tracing(func, args) doesn't take kwargs, which would be great.

This would probably best as a separate issue, IMO, since it doesn't appear to be directly

I think the rule is - you can't do settrace in profiling function and you can't do setprofile in tracing function.

Is this documented anywhere? It might be worth adding a small note in the docs of the respective functions.

@impact27
Copy link
Contributor Author

impact27 commented Mar 13, 2023

From what I can see, the rule is that if you need to call settrace or setprofile in a profiling / tracing function you need sys.call_tracing. There does not appear to be any fundamental difference between settrace and setprofile in that regard. This is the approach spyder uses to profile while debugging or to do recursive debugging.

@CAM-Gerlach
Copy link
Member

In that case, perhaps we should add a note to that effect. Are you interested in submitting a PR? Happy to help guide you in that since I'm one of the docs team members here.

impact27 added a commit to impact27/cpython that referenced this issue Mar 18, 2023
@impact27
Copy link
Contributor Author

I opened #102806

hugovk pushed a commit that referenced this issue Oct 31, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 31, 2023
(cherry picked from commit 2445673)

Co-authored-by: Quentin Peter <[email protected]>
Co-authored-by: C.A.M. Gerlach <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 31, 2023
(cherry picked from commit 2445673)

Co-authored-by: Quentin Peter <[email protected]>
Co-authored-by: C.A.M. Gerlach <[email protected]>
hugovk pushed a commit that referenced this issue Oct 31, 2023
hugovk pushed a commit that referenced this issue Oct 31, 2023
@hugovk
Copy link
Member

hugovk commented Oct 31, 2023

Thanks!

@hugovk hugovk closed this as completed Oct 31, 2023
FullteaR pushed a commit to FullteaR/cpython that referenced this issue Nov 3, 2023
aisk pushed a commit to aisk/cpython that referenced this issue Feb 11, 2024
Glyphack pushed a commit to Glyphack/cpython that referenced this issue Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

6 participants