yappi icon indicating copy to clipboard operation
yappi copied to clipboard

SystemError using Yappi for Python3.13 Free Threaded

Open dan-glass opened this issue 1 year ago • 1 comments
trafficstars

I am having trouble getting Yappi to work with Python 3.13t Free Threading. Attempting to isolate the issue, the smallest example was using unittest.patch. However I am able to see it with other libraries, notably a c binary accessed via ctypes. The issue occurs whether the GIL is disabled or not.

Code

#!/usr/bin/env python3.13t
import yappi
import unittest
from unittest.mock import patch
import sys
print(sys.version)

class TestReadFile(unittest.TestCase):

    def setUp(self):
        yappi.start()

    @patch('builtins.open')
    def test_read_file(self, mock_file):
        pass


if __name__ == '__main__':
    unittest.main()

Command

./test_yappi.py
PYTHON_GIL=1 ./test_yappi.py

Output

# ./test_yappi.py
3.13.0 experimental free-threading build (main, Oct  8 2024, 08:51:27) [GCC 9.4.0]
E
======================================================================
ERROR: test_read_file (__main__.TestReadFile.test_read_file)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3.13/unittest/mock.py", line 686, in __getattr__
    elif self._mock_methods is not None:
         ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/unittest/mock.py", line 685, in __getattr__
    raise AttributeError(name)
AttributeError: _mock_methods

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/lib/python3.13/unittest/mock.py", line 1420, in patched
    with self.decoration_helper(patched,
         ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
                                args,
                                ^^^^^
                                keywargs) as (newargs, newkeywargs):
                                ^^^^^^^^^
  File "/usr/lib/python3.13/contextlib.py", line 141, in __enter__
    return next(self.gen)
  File "/usr/lib/python3.13/unittest/mock.py", line 1402, in decoration_helper
    arg = exit_stack.enter_context(patching)
  File "/usr/lib/python3.13/contextlib.py", line 530, in enter_context
    result = _enter(cm)
  File "/usr/lib/python3.13/unittest/mock.py", line 1549, in __enter__
    new = Klass(**_kwargs)
  File "/usr/lib/python3.13/unittest/mock.py", line 2156, in __init__
    def __init__(self, /, *args, **kw):

SystemError: <sys.legacy_event_handler object at 0x48614a4a950> returned a result with an exception set

----------------------------------------------------------------------
Ran 1 test in 0.005s

FAILED (errors=1)

Dockerfile

FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN add-apt-repository -y ppa:deadsnakes/ppa
RUN apt-get install -y \
    	python3.13-nogil \
    	libpython3.13-nogil \
    	libpython3.13-dev

dan-glass avatar Nov 04 '24 04:11 dan-glass

Thanks for the reproducer!

I will look into this.

sumerc avatar Nov 07 '24 16:11 sumerc

@sumerc are you interested in some help to get yappi working on the free-threaded build? My team @quansight-labs is working on ecosystem support for free-threaded python and yappi came up on our list of packages we'd like to work on to unblock work in the ecosystem.

We'd appreciate your thoughts, if any, on whether an outside contributor could take this on and what ideas you have about this.

ngoldbaum avatar Aug 21 '25 14:08 ngoldbaum

Hi,

Sure I will be pretty much interested and ok with an outside contributor.

But, my question would be:

There is lots of global data structures and implicit assumptions that rely on GIL being held. Do you think it's worth the effort? My mental model is: I am skeptical about having a true parallelism in a profiler that tries to do as little as possible for each function entry/exit would add any benefit? No? I mean adding locks(if we are going to do that) might even make perf. worse?

Maybe I am missing some parts/implementation details...etc.

sumerc avatar Aug 29 '25 09:08 sumerc

There is lots of global data structures

You weren't kidding!

I am skeptical about having a true parallelism in a profiler that tries to do as little as possible for each function entry/exit would add any benefit? No? I mean adding locks(if we are going to do that) might even make perf. worse?

It may be possible to do it in a lock-free way with atomics or thread-locals.

That said, I'm not super familiar with this tool and would need some time to get acquainted with the codebase to see what makes sense. I know that some of the Memray team have recently been spending a lot of effort getting that tool working under the free-threaded build. There are also some new tracing APIs that may be useful. I'll sync back with our team and with some of the CPython core devs we're working with to get their opinion.

ngoldbaum avatar Aug 29 '25 16:08 ngoldbaum

Fair enough!

Pls also don't hesitate to ping/discuss/involve me for anything! This is really an interesting direction.

sumerc avatar Aug 30 '25 14:08 sumerc

We talked about this and found that the dependency on yappi we encountered wasn’t actually in the critical path for any other projects, so we decided to not focus on this given the expected technical complexity. I’ll let you know if that changes in the future.

ngoldbaum avatar Oct 07 '25 16:10 ngoldbaum