Skip to content

Add tier 2 partial evaluation pass. #120619

Open

Description

@markshannon

Once an optimization pass is in place, it enables external contributors to make improvements.
It happened with the tier 1 specializer and is happening now with the tier 2 optimizer and JIT.
We should add the partial evaluation pass, so that external contributors can help with that.

The aim of the partial evaluation pass is to do computation, allocation and deallocation during optimization, so it doesn't need to be done at runtime.

We should add this pass, starting with a few very simple optimizations as placeholders for the full pass to be added later.
These optimizations should include:

  • Float unboxing
  • Temporary tuple elimination

We can start with the very simple optimization : BUILD_TUPLE 2; _RETURN_VALUE; UNPACK 2 -> _RETURN_PAIR before adding more complex optimizations in the future.

Linked PRs

Activity

  1. added
    performancePerformance or resource usage
    interpreter-core(Objects, Python, Grammar, and Parser dirs)
    3.14bugs and security fixes
    on Jun 17, 2024
  2. added a commit that references this issue on Jun 17, 2024
  3. added a commit that references this issue on Jun 30, 2024
  4. added a commit that references this issue on Jul 11, 2024
  5. Fidget-Spinner commented on Jul 16, 2024

    @Fidget-Spinner
    Member

    @markshannon do you mind if I assign myself to this?

  6. added a commit that references this issue on Jul 17, 2024
  7. markshannon commented on Jul 18, 2024

    @markshannon
    MemberAuthor

    This is a fairly large feature, so I'd like to do some reasonably detailed design work before we start implementing this.

    Fell free to add any thoughts you have about the design here, or in https://github.com/faster-cpython/ideas, but I'd advise against starting coding just yet.

  8. Fidget-Spinner commented on Sep 1, 2024

    @Fidget-Spinner
    Member

    I propose this algorithm, starting with the simplest optimization: LOAD_FAST; POP_TOP -> _NOP, or constant propagation.
    faster-cpython/ideas#561 (comment)

  9. added a commit that references this issue on Oct 2, 2024
  10. added a commit that references this issue on Nov 9, 2024
  11. added a commit that references this issue on Dec 8, 2024
  12. added a commit that references this issue on Jan 12, 2025
  13. Fidget-Spinner commented on Feb 14, 2026

    @Fidget-Spinner
    Member

    Design

    Required background knowledge:

    • Abstract interpretation. Recommended reading by me: Tutorial on Static Inference of Numeric Invariants by Abstract Interpretation (Antoine Miné). The complex relational abstract domains are not required knowledge.
    • Partial evaluation. Recommended reading by me/Mark: Partial Evaluation and Automatic Program Generation by Jones, Gomard and Sestoft). Further reading for tracing JITs: https://dl.acm.org/doi/10.1145/1929501.1929508

    Design:
    Mark's PhD theses showed that partial evaluation in Python is almost useless without specialization, which provides type information. I thus propose the following design:

    1. Create a new PE pass in a new DSL file, with all its required data structures.
    2. The new PE pass shall be run in lockstep fashion after the current types/specialization optimizer pass for each instruction. So it would be SPEC -> PE for every instruction.
      a. This is not new art, as PyPy already runs its analysis in lockstep fashion for every instruction.
    3. The key innovation: this new PE pass would receive information unidirectionally from the specialization pass.
      a. We supply all the type information we already have in the first pass to the second pass. In the literature, this is known as the cardinal product of 2 abstract domains. The abstract domains we are combining are the types lattice and the "shape"/object one). The key benefit is to reduce duplicated code and also increase the power of the second domain. For example, to perform a scalar replacement of tuples, we would need to know anyways that it's a tuple of size n, a type that we already have information about in the types specialization pass.
      b. By defining them as two separate domains, we ensure that they remain conceptually separate and clear.
    4. Testing. We shall have testing modes that allow us to switch off either pass, so that we can individually test the passes still. However, note that the PE pass is not much useful without type information anyways, so there might be no point switching off the types pass just to test the PE pass.
    5. Goals. Start with simple things like object allocation removal of slice objects and tuples on the stack that don't escape. We can expand more later.

    We should discuss the design further and refine it. @reidenong is likely taking the initial implementation up.

    Future direction

    Currently, we just stick the guards onto the end of the trace during the final phase when the executor prepares for execution.

    Unfortunately, if we are to do more complicated optimizations, we will need to reconstruct state before bailing to the interpreter.

    Mainly, we need some way to say "this is the state we need to restore at X point of execution upon exiting", and write the instructions to restore that state then.

    Instead, the optimizer should be able to know what instructions it needs to emit to restore the state. We can have a "guard arena" that stores each guard fragment, so during uop optimization it should look like this:

    Image

    After that pass and during the prepare for execution pass, we merge the guard buffer and main trace into one single buffer, and insert the final _EXIT_TRACE and _DEOPT instructions for each guard fragment while doing so.

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

Metadata

Metadata

Labels

3.14bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usage

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions