Make several attributes stores a SINGLE instruction

Explanation

I’ve been exploring the PEP series on with statement in Python, which I found something interesting about VB language, the VB’s with statement, with which you can do this:

With theCustomer
    .Name = "Coho Vineyard"
    .URL = "http://www.cohovineyard.com/"
    .City = "Redmond"
End With

In the __init__method of Python classes, we often do this:

class Spam:
    def __init__(self, a, b, c, d, e, f):
         self.a = a
         self.b = b
         self.c = c
         self.d = d
         self.e = e
         self.f = f

If we look at the bytecode of Spam class:


There are two performance penalties:

  • 6 LOAD_FAST’s for self
  • 6 STORE_ATTR instruction (one per attrubute)

Even if we cache self in the execution (which I don’t know if Python does that or not,) we will still have one STORE_ATTR for each of the attibute stores on self.

What if we had one byte code to do several STORE_ATTRs at once?**

Consider this series of byte code:

  1           0 LOAD_FAST                0 (self)
              2 LOAD_FAST                1 (a)
              4 LOAD_FAST                2 (b)
              6 LOAD_FAST                3 (c)
              8 LOAD_FAST                4 (d)
             10 LOAD_FAST                5 (e)
             12 LOAD_FAST                6 (f)
             14 **STORE_ONCE**           7
             16 POP_TOP
             28 LOAD_CONST               0 (None)
             20 RETURN_VALUE

Doing several I/O operation like memory access, like what we do now (several STORE_ATTR on one object) is slow. If there were an instruction like STORE_ONCE and doing the store on the object in one instruction, many ceval.c loops’ time would be saved and execution would be faster.

Syntax

For the syntax I’ve came up with a syntax like the VB’s, but after talking with my friends they suggested a cleaner syntax:

class Spam:
    def __init__(self, a, b, c, d, e, f):
        self.(
            a=a, b=b, c=c, d=d, e=e, f=f
        )

This idea is not limited to just __init__ method, anywhere we can use this:

object.(attr1=arg1, attr2=arg2, attr3=arg3, ...)

and the generated byte code for this will be named: STORE_ONCE and CPython will access memory once and assign the properties at once.

But one restriction is that we must use keyword only arguments on this.

Faster CPython

I think this idea is more related to Faster CPython team
@markshannon
@brandtbucher
(sorry if you are one of the team and I missed you, I just knew these people. I saw the Members · People · faster-cpython · GitHub)

I thank you for the time you spent on reading this and I really appreciate any feedback on this post.
Thank you

1 Like

Hi, I think this syntax has been suggested under various forms already but never gained traction with the core devs (but many users like the idea). The general consensus seems to be that if you want to remove the boilerplate you use dataclasses.

Regarding performance, IIUC the tracing in the tier 2 optimizer should be able to remove most of the LOAD_FAST (self)s, bit I don’t fully understand how the tier 2 interpreter works

Thanks for you reply.

No, the post main focus is performance related. But, as a side effect, it’ll remove the boilderplate as well. What I really want is a new mechanism in the CPython to do the store once.

Oh, that’s nice :grin: I didn’t know that. Thanks

1 Like

Yeah I wasn’t very clear that I think the proposed optimization seem like it could be useful, and that my reply only covered the proposed syntax.

And yeah, the tier 2 optimizer seems pretty neato and I can’t wait to try it in 3.13, especially if the JIT lands in that release!

3 Likes

Hi @ambv :grin:
would you please read my ‘idea’, and say you opinion? I’ll be very gratefull

(post deleted by author)

@mahdihaghverdi, hi. Please avoid pinging people in person unless it’s an urgent matter. We tend to get a lot of notifications. It’s especially unhelpful in times when a lot of people are on vacation (you pinged me on New Year’s day without any wishes? :smiling_face_with_tear:).

As for your idea, we are moving away from specialized macro-opcodes in favor of a new T2 interpreter running the opposite: micro-operations that lend themselves well for JITting. So, at least for now, we will not be going forward with your idea.

Happy New Year!

3 Likes

Happy new ping, you now have 2024 unread notifications! :expressionless:

1 Like

Now I do :nerd_face:

1 Like

I’m really glad for your answer :grin::grin:

Oh, yes you’re right im sorry for pinging

At that time, i really forgot that it was new year (our calendar is different, our new year is when the spring starts) so Happy New Year Mr. Langa. I wish you have a great 2024 :grin:

I see, thanks for the explanations :ok_hand:

2 Likes