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

Run leakchecks on Python 3.7 #1197

Closed
jamadden opened this Issue May 4, 2018 · 2 comments

Comments

Projects
None yet
1 participant
@jamadden
Member

jamadden commented May 4, 2018

  • gevent version: 1.3
  • Python version: 3
  • Operating System: Linux/macOS

Description:

We currently run these on CPython 2.7. The first time I tried to run them on Python 3 it was a mess. 3.7's cleanup of the way frame objects handle references should hopefully simplify things.

With luck we'll only need to tweak the rules in src/greentest/greentest/leakcheck.py to get a clean run.

@jamadden jamadden added this to the 1.3 milestone May 4, 2018

@jamadden

This comment has been minimized.

Member

jamadden commented May 4, 2018

And the results of 'make leaktest':

! GEVENTTEST_LEAKCHECK=1   //python37b4 -u test__pool.py [code TIMEOUT] [took 100.0s]
Running tests marked standalone
+ GEVENTTEST_LEAKCHECK=1   //python37b4 -u test__examples.py
- GEVENTTEST_LEAKCHECK=1   //python37b4 -u test__examples.py [took 8.9s]
+ GEVENTTEST_LEAKCHECK=1   //python37b4 -u test__threadpool.py
- GEVENTTEST_LEAKCHECK=1   //python37b4 -u test__threadpool.py [took 52.5s]

5/112 unexpected passes
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__core.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__api.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__hub.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__select.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__socket_close.py

16/112 tests failed in 03:06

9/112 expected failures
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__api_timeout.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__exc_info.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__event.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__greenletset.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__greenlet.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__queue.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__socket_dns.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__systemerror.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__timeout.py

7/112 unexpected failures
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__semaphore.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__server.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__server_pywsgi.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__socket_dns6.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__pywsgi.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__subprocess.py
 - GEVENTTEST_LEAKCHECK=1  //python37b4 -u test__pool.py

It's nice to see 5 tests that "leaked" on Python 2 don't on Python 3.7.

Of the failures, lots of the leaked refs are 'internal' python details: cell, method, function, getset_descriptor, builtin_function_or_method. Perhaps some of those need to be added to the excluded types in leakcheck.py, but it will take some study.

Lots of them are various exception classes (chaining?). Representative from test_socket_dns:

  ======================================================================
  FAIL: test_port_string (__main__.Test_getnameinfo_fail)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "//src/greentest/greentest/leakcheck.py", line 132, in wrapper
      raise AssertionError('refcount increased by %r\n%s' % (deltas, diff))
  AssertionError: refcount increased by [3, 2, 2, 2]
  <class 'TypeError'>: 2 != 4

But there are clearly some substantial differences, especially when it comes to sockets or pywsgi. Representative pywsgi:

  ======================================================================
  FAIL: test_chunked_readline (__main__.ChunkedInputTests)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "//src/greentest/greentest/leakcheck.py", line 132, in wrapper
      raise AssertionError('refcount increased by %r\n%s' % (deltas, diff))
  AssertionError: refcount increased by [39, 24, 24, 24]
  <class '_io.BufferedReader'>: 2 != 3
  <class 'socket.SocketIO'>: 1 != 2
  <class 'gevent._socket3._wrefsocket'>: 1 != 2
  <class 'builtin_function_or_method'>: 1063 != 1064
  <class 'cell'>: 1229 != 1234
  <class 'function'>: 6413 != 6416
  <class 'getset_descriptor'>: 1100 != 1102
  <class 'method'>: 136 != 137
  <class 'gevent._socket3.socket'>: 1 != 2
  <class 'type'>: 851 != 852
  <class 'weakref'>: 1749 != 1750
@jamadden

This comment has been minimized.

Member

jamadden commented May 4, 2018

Yup, the bulk of the exception problems were chaining. We were raising a static exception object, and as the leaktests repeat over and over, the refs build up.

I've also dropped the bulk of our own refcounting code in favor of objgraph. The idea is that it will make debugging leaks easier (though so far I haven't really had to use that).

Switching to objgraph (and avoiding too many closures) also helped.

jamadden added a commit that referenced this issue May 4, 2018

Run leakchecks on Python 3.7.
Fixes #1197

Switch to objgraph to handle the measurement for us. That cleared up a
few of the obscure issues with references to
functions/getset_descriptors and the like. (Possibly because it keys
by string names and we were keeping type objects alive.)

Many of the real failures were due to re-using exception instances,
which is bad because of chaining.

Most of the @ignore_leakcheck are for performance, only one is for a
real issue---and that test was skipped already on CI anyway for being
too flaky.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment