GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — bpo-45565: Specialize LOAD_ATTR_CLASS by Fidget-Spinner · Pull Request #29146 · python/cpython

Conversation

@Fidget-Spinner

@Fidget-Spinner Fidget-Spinner commented Oct 22, 2021 •
edited by bedevere-bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Almost same as LOAD_METHOD_CLASS.

https://bugs.python.org/issue45565

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

corona10 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@Fidget-Spinner
Specialize LOAD_ATTR_CLASS
61c3a5b
@Fidget-Spinner
Fidget-Spinner requested a review from markshannon as a code owner October 22, 2021 07:16
@bedevere-bot bedevere-bot added the awaiting core review label Oct 22, 2021
@the-knights-who-say-ni the-knights-who-say-ni added the CLA signed label Oct 22, 2021
@Fidget-Spinner

Fidget-Spinner commented Oct 22, 2021

Copy link
Copy Markdown
Member Author

Stats for python -m test_typing test_re test_dis test_zlib.

Before:
    load_attr.specialization_success : 594
    load_attr.specialization_failure : 8409
    load_attr.hit : 1058930
    load_attr.deferred : 496229
    load_attr.miss : 8925
    load_attr.deopt : 124
    load_attr.unquickened : 11868

After adding LOAD_METHOD_CLASS:
    load_attr.specialization_success : 718
    load_attr.specialization_failure : 8121
    load_attr.hit : 1068789
    load_attr.deferred : 484066
    load_attr.miss : 11229
    load_attr.deopt : 149
    load_attr.unquickened : 11868
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner
Add news
ee7a76a
@markshannon

markshannon commented Oct 22, 2021

Copy link
Copy Markdown
Member

Do you have stats for the standard benchmark suite (or something of similar scale), and have you benchmarked this?

A couple of things that stand out:

  • For the stats you give, the hits increase by ~10k and the misses increase by ~2k. The cost of a miss can be higher than the benefit of a hit so this might not be a win. Is this an artifact of the test scripts? Would you expect better numbers on "real" programs?
  • The cache use for LOAD_ATTR has increased from 2 to 3. Only 4 bytes of each of the first two cache entries are being used, so this could be reduced back to 2 entries.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner

Fidget-Spinner commented Oct 22, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Do you have stats for the standard benchmark suite (or something of similar scale), and have you benchmarked this?

No, I'll get some soon (pyperformance is a pain on Windows :().

  • For the stats you give, the hits increase by ~10k and the misses increase by ~2k. The cost of a miss can be higher than the benefit of a hit so this might not be a win. Is this an artifact of the test scripts? Would you expect better numbers on "real" programs?

The only possible way for deopt is for tp_version_tag to change, and that requires the class variable to be written to. So things like:

class X:
 x = 1

X.x = 2

Unfortunately, I have no clue how common something like this is in the real world. An alternative approach (with far fewer invalidations):

  1. Store owner.tp_mro tuple ID.
  2. Store the index of the real type we need to look into and where it belongs in owner.tp_mro.
  3. Store dict hint of real type.__dict__ and dk version..

At runtime, look into owner.tp_mro[mro_index].__dict__ + hint to get our attribute.

The benefit is that tp_version_tag invalidates every time a write occurs, but we don't care about that since the actual index in the dict doesn't change.

  • The cache use for LOAD_ATTR has increased from 2 to 3. Only 4 bytes of each of the first two cache entries are being used, so this could be reduced back to 2 entries.

Indeed, I failed to see that _PyAdaptiveEntry still had 4 bytes of unused space, so we can pack tp_version_tag into there if we go with the old approach.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner

Fidget-Spinner commented Oct 22, 2021

Copy link
Copy Markdown
Member Author

Wow, somehow the stats for the alternative approach (mentioned above) is almost exactly the same as the old one using tp_version_tag 😮 . I clearly don't know enough about how types work in Python, or the test suite is doing some weird stuff.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed Oct 28, 2021
View reviewed changes
Comment thread Python/ceval.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Fidget-Spinner added 4 commits October 28, 2021 23:15
@Fidget-Spinner
use approach 2
39afbd4
@Fidget-Spinner
Merge remote-tracking branch 'upstream/main' into load_attr_class
ba77a34
@Fidget-Spinner
regen opcodes
f6f1b2a
@Fidget-Spinner
dont print spec stats
d847bb6
@Fidget-Spinner

Fidget-Spinner commented Oct 28, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Some comments:
the method cache/tp_version_tag people were very smart. After 8 tries in the following loop, the method cache gives up and tp_version_tag remains 0 to prevent cache thrashing.

class X:
 x = 1

for _ in range(20):
 X.x
 print(_testcapi.type_get_version(X))
 X.x = None

However, approach 2 using MRO index works even with the test case above, some stats for the code:

class X:
 x = 1

for _ in range(100000):
 X.x
 X.x = None

# Approach 1, using tp_version_tag
    load_attr.specialization_success : 903
    load_attr.specialization_failure : 72
    load_attr.hit : 2342
    load_attr.deferred : 54713
    load_attr.miss : 45117
    load_attr.deopt : 848
    load_attr.unquickened : 912

# Approach 2, using MRO index, no tp_version_tag
    load_attr.specialization_success : 56  (this stat is wonky)
    load_attr.specialization_failure : 72
    load_attr.hit : 101487
    load_attr.deferred : 505
    load_attr.miss : 180
    load_attr.deopt : 1
    load_attr.unquickened : 912
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions

github-actions Bot commented Nov 28, 2021

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Nov 28, 2021
@ezio-melotti ezio-melotti removed the CLA signed label Jul 13, 2022
@iritkatriel

iritkatriel commented Sep 9, 2022

Copy link
Copy Markdown
Member

@Fidget-Spinner Is this abandoned, or are you planning to continue working on it?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner

Fidget-Spinner commented Sep 10, 2022

Copy link
Copy Markdown
Member Author

@iritkatriel this was completed in #93430). Thanks for the reminder!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Fidget-Spinner Fidget-Spinner closed this Sep 10, 2022
@Fidget-Spinner Fidget-Spinner mentioned this pull request Sep 10, 2022
More LOAD_ATTR specializations #89728
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@markshannon markshannon markshannon left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

awaiting core review stale Stale PR or inactive for long period of time.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@Fidget-Spinner @markshannon @iritkatriel @the-knights-who-say-ni @ezio-melotti @bedevere-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.