faster-cpython / ideas

1.67k stars 49 forks source link

`LOAD_CONST_IMMORTAL` #584

Closed markshannon closed 6 months ago

markshannon commented 1 year ago

Constants are, um, constant. So if the argument of LOAD_CONST is immortal is will always be immortal.

We could add a specialization of LOAD_CONST, LOAD_CONST_IMMORTAL, which doesn't do any refcount modification.

The neatest way to do this would be in the compiler, but it can be done at runtime:

inst(LOAD_CONST, (-- value)) {
    value = GETITEM(frame->f_code->co_consts, oparg);
    if (_Py_IsImmortal(value)) {
        next_instr[-1].op.code = LOAD_CONST_IMMORTAL;
    }
    else {
        Py_INCREF_UNCONDITIONAL(value);
    }
}

A LOAD_CONST_MORTAL specialization is not possible, as PEP 683 allows mortal object to become immortal.

brandtbucher commented 1 year ago

Assigning myself, since I already have a branch that does this in the compiler (no speedup, though, which is why it was put on pause).

brandtbucher commented 1 year ago

See https://github.com/python/cpython/compare/main...brandtbucher:cpython:load-const-immortal. It currently handles None, True, False and the small integers.

I'll try benchmarking it tonight, and if it's no faster I can also add support for the empty tuple and 0/1-character ASCII str/bytes as well. I also haven't yet looked into whether RETURN_CONST should become RETURN_CONST_IMMORTAL (I suspect it should, since that was the case for the LOAD_CONST superinstructions).

markshannon commented 1 year ago

Note that LOAD_CONST_IMMORTAL is different from the LOAD_CONST_COMMON that you were experimenting with. LOAD_CONST_IMMORTAL can handle any immortal object, but still requires the constants to be added to the code object, so is less space efficient.

It seems unlikely that we will want both forms.

LOAD_CONST_IMMORTAL is a lot simpler to implement, but I suspect that LOAD_CONST_COMMON would be better once we have the infrastructure to find and enumerate the most commonly used constants.

We should remove RETURN_CONST https://github.com/faster-cpython/ideas/issues/577

markshannon commented 6 months ago

Since many constants are strings that can be immortalized when interning, we don't necessarily know what will be immortal at compile time, but we will know when optimizing tier 2. Since we already convert LOAD_CONST to inline versions in tier 2, I'm closing this.