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 — Use dedicated opcodes to speed up calls/attribute lookups with super() as receiver · Issue #87729 · python/cpython

Use dedicated opcodes to speed up calls/attribute lookups with super() as receiver #87729

New issue
Copy link
New issue
Copy link
Closed
#103809
Closed
Use dedicated opcodes to speed up calls/attribute lookups with super() as receiver#87729
#103809
Copy link
Labels
3.10 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)

Description

vladima
mannequin
opened on Mar 19, 2021
Issue body actions
BPO 43563
Nosy @gvanrossum, @rhettinger, @markshannon, @vladima, @isidentical
PRs
  • bpo-43563 : Introduce dedicated opcodes for super calls #24936
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-03-19.20:57:57.938>
    labels = ['interpreter-core', '3.10']
    title = 'Use dedicated opcodes to speed up calls/attribute lookups with super() as receiver'
    updated_at = <Date 2021-04-27.18:23:03.781>
    user = 'https://github.com/vladima'

    bugs.python.org fields:

    activity = <Date 2021-04-27.18:23:03.781>
    actor = 'v2m'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2021-03-19.20:57:57.938>
    creator = 'v2m'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 43563
    keywords = ['patch']
    message_count = 7.0
    messages = ['389114', '389156', '389168', '389337', '389340', '389344', '392116']
    nosy_count = 5.0
    nosy_names = ['gvanrossum', 'rhettinger', 'Mark.Shannon', 'v2m', 'BTaskaya']
    pr_nums = ['24936']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue43563'
    versions = ['Python 3.10']

    Linked PRs

    • gh-87729: add LOAD_SUPER_ATTR instruction for faster super() #103497
    • gh-87729: specialize LOAD_SUPER_ATTR_METHOD #103809
    • gh-87729: improve hit rate of LOAD_SUPER_ATTR specialization #104270
    • gh-87729: add LOAD_SUPER_ATTR to 3.12 What's New #105125
    • [3.12] gh-87729: add LOAD_SUPER_ATTR to 3.12 What's New (GH-105125) #105143

    Activity

    1. vladima commented on Mar 19, 2021

      @vladima
      vladimamannequin
      on Mar 19, 2021
      MannequinAuthor
      More actions

      Calling methods and lookup up attributes when receiver is super() has extra cost comparing to regular attribute lookup. It mainly comes from the need to allocate and initialize the instance of the super which for zero argument case also include peeking into frame/code object for the __class__ cell and first argument. In addition because PySuper_Type has custom implementation of tp_getattro - _PyObject_GetMethod would always return bound method.

      import timeit
      
      setup = """
      class A:
          def f(self): pass
      class B(A):
          def f(self): super().f()
          def g(self): A.f(self)
      b = B()
      """
      print(timeit.timeit("b.f()", setup=setup, number=20000000))
      print(timeit.timeit("b.g()", setup=setup, number=20000000))
      
      7.329449548968114
      3.892987059080042
      

      One option to improve it could be to make compiler/interpreter aware of super calls so they can be treated specially. Attached patch introduces two new opcodes LOAD_METHOD_SUPER and LOAD_ATTR_SUPER that are intended to be counterparts for LOAD_METHOD and LOAD_ATTR for cases when receiver is super with either zero or two arguments.

      Immediate argument for both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER is a pair that consist of:
      0: index of method/attribute in co_names
      1: Py_True if super was originally called with 0 arguments and Py_False otherwise.

      Both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER expect 3 elements on the stack:
      TOS3: global_super
      TOS2: type
      TOS1: self/cls

      Result of LOAD_METHOD_SUPER is the same as LOAD_METHOD.
      Result of LOAD_ATTR_SUPER is the same as LOAD_ATTR

      In runtime both LOAD_METHOD_SUPER and LOAD_ATTR_SUPER will check if global_super is PySuper_Type to handle situations when super is patched. If global_super is PySuper_Type then it can use dedicated routine to perform the lookup for provided __class__ and cls/self without allocating new super instance. If global_super is different from PySuper_Type then runtime will fallback to the original logic using global_super and original number of arguments that was captured in immediate.

      Benchmark results with patch:
      4.381768501014449
      3.9492998640052974

    2. vladima
      added
      3.10 (EOL)end of lifeend of life
      interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
      on Mar 19, 2021
    3. markshannon commented on Mar 20, 2021

      @markshannon
      markshannon
      on Mar 20, 2021
      Member
      More actions

      Why?

      Do you have any evidence that the overhead of super() is significant in real programs, or that the proposed change actually speeds up anything beyond your micro-benchmark?

    4. rhettinger commented on Mar 20, 2021

      @rhettinger
      rhettinger
      on Mar 20, 2021
      Contributor
      More actions

      Currently, super() is decoupled from the core language. It is just a builtin that provides customized attribute lookup. This PR makes super() more tightly integrated with the core language, treating it as if it were a keyword and part of the grammar. Also note, users can currently create their own versions of super(), shadowing the builtin super().

    5. vladima commented on Mar 22, 2021

      @vladima
      vladimamannequin
      on Mar 22, 2021
      MannequinAuthor
      More actions

      Currently, super() is decoupled from the core language. It is just a builtin that provides customized attribute lookup. This PR makes super() more tightly integrated with the core language, treating it as if it were a keyword and part of the grammar. Also note, users can currently create their own versions of super(), shadowing the builtin super().

      This is true however:

      • this patch does not block people from introducing custom version of super so this scenario still work. The idea was to streamline the common case
      • based on digging into Instagram codebase and its transitive dependencies (which is reasonably large amount of code) all spots where super() appear in sources assume super to be builtin and for a pretty common use-case its cost is noticeable in profiler.
      • zero-argument super() still a bit magical since it requires compiler support to create cell for __class__ and assumes certain shape of the frame object so this patch is a step forward with a better compiler support and removing runtime dependency on the frame

      Do you have any evidence that the overhead of super() is significant in real programs

      I do see the non-negligible cost of allocation/initialization of super object in IG profiling data.

    6. gvanrossum commented on Mar 22, 2021

      @gvanrossum
      gvanrossum
      on Mar 22, 2021
      Member
      More actions

      This looks like a sensible idea to me. The safeguards to ensure that customized 'super' still works seem reasonable to me. I have to admit that I sometimes refrain from using super() where I should because of the expense, so this would be welcome.

      I do wonder -- is two-arg super() important enough to support it at all? Maybe the code would be somewhat simpler if the special opcodes were only generated for zero-arg super() calls.

    7. markshannon commented on Mar 22, 2021

      @markshannon
      markshannon
      on Mar 22, 2021
      Member
      More actions

      Numbers please.

      What is "non-negligible cost of allocation/initialization" mean as a fraction of runtime?
      What sort of speed up are you seeing on whole programs?

    8. vladima commented on Apr 27, 2021

      @vladima
      vladimamannequin
      on Apr 27, 2021
      MannequinAuthor
      More actions

      Apologies for the delay in reply: in more concrete numbers for IG codebase enabling this optimization resulted in 0.2% CPU win.

    9. ezio-melotti
      transferred this issue fromon Apr 10, 2022
    10. carljm
      added a commit that references this issue on Apr 13, 2023

      pythongh-87729: add instruction for faster zero-arg super()

      0a0ebe2
    11. carljm
      added 2 commits that reference this issue on Apr 24, 2023

      gh-87729: add LOAD_SUPER_ATTR instruction for faster super() (#103497)

      0dc8b50

      Merge branch 'main' into superopt_spec

      af807d6
    12. carljm
      closed this as completedin #103809on Apr 25, 2023
    13. carljm
      added a commit that references this issue on Apr 25, 2023

      gh-87729: specialize LOAD_SUPER_ATTR_METHOD (#103809)

      ef25feb
    14. itamaro
      added a commit that references this issue on Apr 26, 2023

      pythongh-87729: specialize LOAD_SUPER_ATTR_METHOD (python#103809)

      bf717d4
    15. carljm
      added 3 commits that reference this issue on May 7, 2023

      pythongh-87729: improve hit rate of LOAD_SUPER_ATTR specialization

      5b64c58

      gh-87729: improve hit rate of LOAD_SUPER_ATTR specialization (#104270)

      7726245

      Merge branch 'main' into supermon

      fb47955
    16. carljm
      added 2 commits that reference this issue on May 31, 2023

      pythongh-87729: add LOAD_SUPER_ATTR to 3.12 What's New

      65b96ed

      gh-87729: add LOAD_SUPER_ATTR to 3.12 What's New (#105125)

      7fbac51
    17. miss-islington
      added a commit that references this issue on May 31, 2023

      pythongh-87729: add LOAD_SUPER_ATTR to 3.12 What's New (pythonGH-105125)

      b7c2029
    18. carljm
      added a commit that references this issue on May 31, 2023

      [3.12] gh-87729: add LOAD_SUPER_ATTR to 3.12 What's New (GH-105125) (#…

      4f477c7
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.10 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        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.