Skip to content
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

bpo-42927: Inline cache for slots #24216

Merged
merged 7 commits into from Jan 30, 2021
Merged

bpo-42927: Inline cache for slots #24216

merged 7 commits into from Jan 30, 2021

Conversation

@gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Jan 14, 2021

This is a modification of the LOAD_ATTR inline cache that landed a few months ago (PR 22803).

The design overloads the hint field: if it is negative, it indicates a slot. Slots are created using __slots__, but some builtin types that use PyMemberDescrObject descriptors (with the type set to T_OBJECT_EX) will also benefit.

I've tried to keep the code style similar to the existing LOAD_ATTR cache (happy path first) but I had to make some compromises, e.g. the cache initialization code can no longer skip everything if tp_dictoffset is zero (since it will be zero for classes with only slots).

https://bugs.python.org/issue42927

Python/ceval.c Outdated Show resolved Hide resolved
@serhiy-storchaka serhiy-storchaka self-requested a review Jan 14, 2021
@vstinner
Copy link
Member

@vstinner vstinner commented Jan 14, 2021

Python/ceval.c Outdated Show resolved Hide resolved
@pablogsal
Copy link
Member

@pablogsal pablogsal commented Jan 14, 2021

Something is wrong, we are reaching ther error label in the eval loop without an error set (check the CI). (The cache is not active in debug mode so if you want to reproduce compile without --with-pydebug). See this comment: https://github.com/python/cpython/pull/24216/files#r557650392

Python/ceval.c Outdated Show resolved Hide resolved
Python/ceval.c Outdated Show resolved Hide resolved
gvanrossum and others added 3 commits Jan 15, 2021
@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 15, 2021

Okay, assuming the tests pass, this is the version I'm sending for review.

@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 15, 2021

It seems test_ssl on macOS failed, but the other test failures have been resolved. Is that test flaky?

@pablogsal
Copy link
Member

@pablogsal pablogsal commented Jan 15, 2021

It seems test_ssl on macOS failed, but the other test failures have been resolved. Is that test flaky?

Given the nature of this change and the fact that the error says:

ConnectionRefusedError: [Errno 61] Connection refused

I would say is unrelated. I have restarted manually the tests.

@bedevere-bot
Copy link

@bedevere-bot bedevere-bot commented Jan 21, 2021

🤖 New build scheduled with the buildbot fleet by @pablogsal for commit b725a65 🤖

If you want to schedule another build, you need to add the "🔨 test-with-buildbots" label again.

@pablogsal
Copy link
Member

@pablogsal pablogsal commented Jan 21, 2021

LGTM! Let's do a buildbot pass to make sure there are no reference leaks.

@pablogsal
Copy link
Member

@pablogsal pablogsal commented Jan 21, 2021

Seems we are missing something because some of the buildbots are crashing with segmentation faults. For instance:

https://buildbot.python.org/all/#/builders/459/builds/69

test_signature_on_decorated (test.test_inspect.TestSignatureObject) ... ok
Fatal Python error: Segmentation fault
Current thread 0x00007fff99164920 (most recent call first):
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/inspect.py", line 2304 in _signature_from_callable
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/inspect.py", line 2877 in from_callable
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/inspect.py", line 3129 in signature
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/test_inspect.py", line 2392 in test_signature_on_decorated_builtins
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/case.py", line 549 in _callTestMethod
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/case.py", line 592 in run
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/case.py", line 652 in __call__
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/suite.py", line 122 in run
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/suite.py", line 84 in __call__
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/suite.py", line 122 in run
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/suite.py", line 84 in __call__
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/unittest/runner.py", line 176 in run
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/support/__init__.py", line 959 in _run_suite
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/support/__init__.py", line 1082 in run_unittest
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/test_inspect.py", line 4062 in test_main
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/runtest.py", line 236 in _runtest_inner2
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/runtest.py", line 272 in _runtest_inner
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/runtest.py", line 155 in _runtest
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/runtest.py", line 195 in runtest
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/main.py", line 319 in rerun_failed_tests
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/main.py", line 696 in _main
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/main.py", line 639 in main
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/libregrtest/main.py", line 717 in main
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/test/__main__.py", line 2 in <module>
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/runpy.py", line 87 in _run_code
  File "/home/buildbot/buildarea/pull_request.cstratak-RHEL8-ppc64le.lto-pgo/build/Lib/runpy.py", line 197 in _run_module_as_main
Extension modules: _testcapi (total: 1)
make: *** [Makefile:1228: buildbottest] Segmentation fault (core dumped)
program finished with exit code 2
elapsedTime=259.101476

The failures seem to be in test_inspect and test_zipfile

@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 22, 2021

Hm. I think this may happen when _PyDict_GetItemHint() returns -1. Then we set la->hint = -1 and then the next time we get here it is interpreted as a slot hint. I'll come up with a fix.

The problem was that sometimes a hint of -1 could be set, meaning the
dict lookup failed.  My code mistook that for a slot offset.

The fix is simple, because slot offsets can never be 0, so ~offset
can never be -1.

I also cleaned up some comments and a variable name.
@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 28, 2021

Here's the fix. @pablogsal how do I trigger a buildbot run? I can't find that in the devguide.

@pablogsal
Copy link
Member

@pablogsal pablogsal commented Jan 28, 2021

Here's the fix. @pablogsal how do I trigger a buildbot run? I can't find that in the devguide.

You can add the "run with buildbots" label to the PR and the checks should start appearing at the bottom together with Travis and the other CI.

@bedevere-bot
Copy link

@bedevere-bot bedevere-bot commented Jan 28, 2021

🤖 New build scheduled with the buildbot fleet by @pablogsal for commit 4c2eb69 🤖

If you want to schedule another build, you need to add the "🔨 test-with-buildbots" label again.

@bedevere-bot
Copy link

@bedevere-bot bedevere-bot commented Jan 28, 2021

🤖 New build scheduled with the buildbot fleet by @gvanrossum for commit 17c8a95 🤖

If you want to schedule another build, you need to add the "🔨 test-with-buildbots" label again.

// Hint >= 0 is a dict index; hint < 0 is an inverted slot index.
if (la->hint < 0) {
/* Even faster path -- slot hint */
// Hint >= 0 is a dict index; hint == -1 is a dict miss.

This comment has been minimized.

@1st1

1st1 Jan 28, 2021
Member

Oh, right! How did I miss that on review :/

This comment has been minimized.

@gvanrossum

gvanrossum Jan 28, 2021
Author Member

Same way I missed it writing the code. :-(

This code is hairy.

if (la->hint < 0) {
/* Even faster path -- slot hint */
// Hint >= 0 is a dict index; hint == -1 is a dict miss.
// Hint < -1 is an inverted slot offset (offsets are never 0).

This comment has been minimized.

@1st1

1st1 Jan 28, 2021
Member

Maybe clarify that slot offsets are always greater than 1?

This comment has been minimized.

@gvanrossum

gvanrossum Jan 29, 2021
Author Member

I have a comment ready to push:

                        // Hint >= 0 is a dict index; hint == -1 is a dict miss.
                        // Hint < -1 is an inverted slot offset: offset is strictly > 0,
                        // so ~offset is strictly < -1 (assuming 2's complement).

Let me know if you still want improvement.

This comment has been minimized.

@1st1

1st1 Jan 29, 2021
Member

looks good to me

@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 29, 2021

Looks like only 2 buildbots failed.

  • AMD64 FreeBSD Shared PR: Crash in test_gdb with Exception: Command 'gdb -nx --version' failed with exit code 1: stdout='' stderr='ld-elf.so.1: Shared object "libncursesw.so.6" not found, required by "gdb"\n'; also failing are test_subprocess (another libcurses issue) and test_venv (test_deactivate_with_strict_bash_opts fails with a subprocess error).

  • s390x Fedora Refleaks PR: test_curses failed in test_init_pair. Do we know if that passes for master?

This seems a better result than before.

@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 29, 2021

I realized there's another optimization for this case. The code always starts with PyObject *name = GETITEM(names, oparg); which calls PyTuple_GetItem(). But if the fast slot/field path is taken we never need that! However the fast dict hint path does need it, and of course all slow paths need it. So the logic for deciding to get this would be convoluted (it would have to be in various else branches).

Is that worth exploring? It might be hard to prove there's no slowdown for the paths that do need the name. I could put this off to another PR -- if slots become more popular because of this PR we can add it later. :-)

@gvanrossum
Copy link
Member Author

@gvanrossum gvanrossum commented Jan 29, 2021

@1st1
1st1 approved these changes Jan 29, 2021
@gvanrossum gvanrossum merged commit 5c5a938 into python:master Jan 30, 2021
11 checks passed
11 checks passed
Docs
Details
Check for source changes
Details
Check if generated files are up to date
Details
Windows (x86)
Details
Windows (x64)
Details
macOS
Details
Ubuntu
Details
Azure Pipelines PR #20210129.17 succeeded
Details
Travis CI - Pull Request Build Passed
Details
bedevere/issue-number Issue number 42927 found
Details
bedevere/news News entry found in Misc/NEWS.d
@bedevere-bot
Copy link

@bedevere-bot bedevere-bot commented Jan 30, 2021

@gvanrossum: Please replace # with GH- in the commit message next time. Thanks!

@gvanrossum gvanrossum deleted the gvanrossum:slotscache branch Jan 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

7 participants